对类的某个方法临时改写的代码排错
在我询问 “代码中能否对类的某个方法临时改写”,sbwwkmyd 给出其中一种方案的代码,
using System;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
ClsAAA aaa = new ClsAAA();
using (methodWriter32<Action> method = new methodWriter32<Action>(aaa.ff, new Program().nothing))
{
aaa.ff();
}
Console.ReadKey();
}
public void nothing()
{
}
}
class ClsAAA
{
public void ff()
{
Console.WriteLine("OK");
}
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
internal struct unionMethod
{
internal class point
{
public int Point;
}
[System.Runtime.InteropServices.FieldOffset(0)]
public point Point;
[System.Runtime.InteropServices.FieldOffset(0)]
public object Method;
}
internal unsafe struct methodTarget
{
public int* MethodPoint;
public object Target;
public int* TargetPoint;
}
internal class targetPoint
{
public object Target;
}
public unsafe abstract class methodWriterBase32<methodType> : IDisposable
{
private int* methodPoint;
private int method;
public methodWriterBase32(methodType setMethod, methodType getMethod)
{
if (setMethod == null || getMethod == null) throw null;
methodPoint = getPoint(setMethod);
int* getMethodPoint = getPoint(getMethod);
if (methodPoint == getMethodPoint) throw null;
method = *methodPoint;
*methodPoint = *getMethodPoint;
}
protected abstract int* getPoint(methodType method);
public void Set(methodType method)
{
if (method == null) throw null;
*methodPoint = *getPoint(method);
}
public void Dispose()
{
if (method != 0)
{
*methodPoint = method;
method = 0;
}
}
}
public sealed unsafe class staticMethodWriter32<methodType> : methodWriterBase32<methodType>
{
public staticMethodWriter32(methodType setMethod, methodType getMethod) : base(setMethod, getMethod) { }
protected override int* getPoint(methodType method)
{
Delegate methodDelegate = method as Delegate;
if (!methodDelegate.Method.IsStatic) throw null;
unionMethod union = new unionMethod { Method = method };
return (int*)*((int*)*((int*)union.Point.Point + 4) + 2) + 2;
}
}
public sealed unsafe class methodWriter32<methodType> : methodWriterBase32<methodType>
{
public methodWriter32(methodType setMethod, methodType getMethod) : base(setMethod, getMethod) { }
protected override int* getPoint(methodType method)
{
Delegate methodDelegate = method as Delegate;
if (methodDelegate.Method.IsStatic) throw null;
unionMethod union = new unionMethod { Method = method };
int point = union.Point.Point;
int* methodPoint = (int*)point;
while (*methodPoint != point) ++methodPoint;
return (int*)*((int*)*(methodPoint + 2) + 2) + 2;
}
}
}
但我在.NET3.5环境下,不安全代码选择打勾,程序运行出错,
在类 methodWriterBase32 的构建函数中 method = *methodPoint; 这句话,错误信息:
“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”
我也试着改为 .NET 2.0 但它不允许这种写法:
using (methodWriter32<Action> method = new methodWriter32<Action>(aaa.ff, new ClsBBB().ff))
也试着两个分成两个项目,一个用2.0,一个用3.5,仍然是 method = *methodPoint; 这句话同样错误。
我对C#中指针不熟悉,大家能帮我看一下是什么原因吗?
[解决办法]
我#19代码中联合体的定义是错误的,指针定位也是错误的。可以参考fastCSharp.reflection.methodWriter,我这里给个重新写个只支持32位的简易版本
/// <summary>
/// 委托方法与指针联合体
/// </summary>
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
internal struct methodPointUnion
{
/// <summary>
/// 委托方法
/// </summary>
internal sealed class method
{
/// <summary>
/// 委托方法
/// </summary>
public object Method;
}
/// <summary>
/// 委托指针
/// </summary>
private sealed class point
{
/// <summary>
/// 委托指针
/// </summary>
public int Point;
}
/// <summary>
/// 委托指针
/// </summary>
[System.Runtime.InteropServices.FieldOffset(0)]
private point methodPoint;
/// <summary>
/// 委托方法
/// </summary>
[System.Runtime.InteropServices.FieldOffset(0)]
public method Method;
/// <summary>
/// 委托指针
/// </summary>
public unsafe int* Point
{
get
{
int* point = (int*)methodPoint.Point + 4;
if (*point == 0) --point;
return (int*)*((int*)*point + 2) + 2;
}
}
}
/// <summary>
/// 方法重写
/// </summary>
/// <typeparam name="methodType">委托类型</typeparam>
public sealed unsafe class methodWriter<methodType> : IDisposable
{
/// <summary>
/// 方法指针
/// </summary>
private int* methodPoint;
/// <summary>
/// 方法指针值
/// </summary>
private int method;
/// <summary>
/// 是否静态方法
/// </summary>
private bool isStatic;
/// <summary>
/// 方法重写
/// </summary>
/// <param name="method">被重写方法委托</param>
/// <param name="setMethod">待写入的方法委托</param>
public methodWriter(methodType method, methodType setMethod)
{
Delegate methodDelegate = method as Delegate;
if (methodDelegate == null
[解决办法]
setMethod == null) throw null;
Delegate setMethodDelegate = setMethod as Delegate;
isStatic = methodDelegate.Method.IsStatic;
if (isStatic ^ setMethodDelegate.Method.IsStatic) throw null;
if (!isStatic)
{
if (methodDelegate.Target != null && !methodDelegate.Target.GetType().IsClass) throw null;
if (setMethodDelegate.Target != null && !methodDelegate.Target.GetType().IsClass) throw null;
}
methodPointUnion union = new methodPointUnion { Method = new methodPointUnion.method { Method = methodDelegate } };
int* methodPoint = union.Point;
union.Method.Method = setMethodDelegate;
int* setMethodPoint = union.Point;
if (methodPoint == setMethodPoint) throw null;
this.method = *(this.methodPoint = methodPoint);
*methodPoint = *setMethodPoint;
}
/// <summary>
/// 方法重写
/// </summary>
/// <param name="setMethod">待写入的方法委托</param>
public void Set(methodType setMethod)
{
Delegate setMethodDelegate = setMethod as Delegate;
if (setMethodDelegate == null) throw null;
if (isStatic ^ setMethodDelegate.Method.IsStatic) throw null;
if (!isStatic && setMethodDelegate.Target != null && !setMethodDelegate.Target.GetType().IsClass) throw null;
methodPointUnion union = new methodPointUnion { Method = new methodPointUnion.method { Method = setMethodDelegate } };
*methodPoint = *union.Point;
}
/// <summary>
/// 释放方法指针
/// </summary>
public void Dispose()
{
int method = this.method;
this.method = 0;
if (method != 0) *methodPoint = method;
}
}
class ClsAAA技巧确实是没有意义的,我写程序都是为了更方便的解决实际问题。
{
public void ff()
{
Console.WriteLine("OK");
}
}
public void nothing()
{
}
static void Main(string[] args)
{
ClsAAA aaa = new ClsAAA();
using (methodWriter<action> method = new methodWriter<action>(aaa.ff, new Program().nothing))
{
aaa.ff();
}
Console.ReadKey();
}