在我询问 “代码中能否对类的某个方法临时改写”,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#中指针不熟悉,大家能帮我看一下是什么原因吗?
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#中指针不熟悉,大家能帮我看一下是什么原因吗?
解决方案 »
- 大家讨论下 如何看待一个程序员水平高低
- 一个关于winform DrawTools画图程序的问题
- 求一存储过程,大侠们帮帮忙啊!
- vb翻译成C#,调用出错.报"未将对象引用设置到对象的实例"
- 怎样将多个byte[] 合并为一个byte[]??? [在线等,急]
- [求助]一个简单的问题?
- 知道Hashtable的values怎么取得keys
- 高分求救:c#中有什么组件可以用来获取一个网页上的所有的对象object和window
- 如何当控制焦点离开textbox时对textbox中的数据进行检验?
- 找asp.net入门经典!一定是C#写的!!!在线等!
- 几天没休息好,头昏脑胀,求个算法
- c#怎么实现excel作业自动批阅
/// 委托方法与指针联合体
/// </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();
}技巧确实是没有意义的,我写程序都是为了更方便的解决实际问题。
{
get
{
int* point = (int*)methodPoint.Point + 4;
if (*point == 0) --point;
point = (int*)*((int*)*point + 2);
if ((*point & 0x8000000) != 0) return point + 5;
if ((*point & 0x40000000) == 0) return point + 18;
return point + 2;
}
}
现有几个疑问:.Net 2.0 应该不能这样写吧?
using (methodWriter<action> method = new methodWriter<action>(aaa.ff, new Program().nothing))
它会提示:使用泛型 类型“System.Action<T>”需要“1”个类型实参
.Net 2.0 下对应的写法应该是如何?假定您的代码对 .Net 3.5 适应。我测试的结果是,编译通过,但运行时出错:
this.method = *(this.methodPoint = methodPoint);
尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
出错时:methodPoint 值为 0x8d50dbf1
同时VS也显示:*methodPoint = 无法取消对“methodPoint”的引用。指针无效。
倒查结果:
methodPoint 是在 int* methodPoint = union.Point; 赋值的
此时的 union 有值
[size=9px]union {ConsoleApplication3.methodPointUnion} ConsoleApplication3.methodPointUnion
Method {ConsoleApplication3.methodPointUnion.method} ConsoleApplication3.methodPointUnion.method
Method {Method = {Void nothing()}} object {System.Action}
base {Method = {Void nothing()}} System.MulticastDelegate {System.Action}
methodPoint {ConsoleApplication3.methodPointUnion.method} ConsoleApplication3.methodPointUnion.point {ConsoleApplication3.methodPointUnion.method}
Point 0x8d5173f1 int*
*union.Point 无法取消对“*union.Point”的引用。指针无效。 int[/size]
Method {ConsoleApplication3.methodPointUnion.method} ConsoleApplication3.methodPointUnion.method
Method {Method = {Void nothing()}} object {System.Action}
base {Method = {Void nothing()}} System.MulticastDelegate {System.Action}
methodPoint {ConsoleApplication3.methodPointUnion.method} ConsoleApplication3.methodPointUnion.point {ConsoleApplication3.methodPointUnion.method}
Point 0x8d5173f1 int*
*union.Point 无法取消对“*union.Point”的引用。指针无效。 int
methodPoint.Point=20134628(0x1333ae4), point=0x01333af4(疑问1:加4后为什么不是e8,而是f4。疑问2:我从调试窗口中的内存数据窗口中,输入Point-4,亦是显示0x1333ae4地址之内存数据,而不是显示0x1333af0地址之内存数据,为什么?自已解释为对 int* +1就是指内存地址+4)
if (*point == 0) --point;
point地址内存为0,扣减1后变为 0x1333af0,内存此处有一个值(a0 c5 9d 00)
return (int*)*((int*)*point + 2) + 2;
*point=0x009dc5a0地址+2后,按上面的说法,应该是:0x009dc5a8,对应内存值为(e9 db 50 8d),但我再去0x8d50dbe9位置查看内容时,内存全为 ?? ?? ??在内存跳来跳去的过程中,这个结构是什么标准?我们是怎么知道的?
0x009dc5a0还是对的,后面的return就错了。#6已经改成 public unsafe int* Point
{
get
{
int* point = (int*)methodPoint.Point + 4;//静态函数指针
if (*point == 0) --point;//非静态函数,取动态成员函数指针
point = (int*)*((int*)*point + 2);
if ((*point & 0x8000000) != 0) return point + 5;//泛型函数指针
if ((*point & 0x40000000) == 0) return point + 18;//虚函数指针
return point + 2;//普通函数指针
}
}0x80000000不是用户空间地址,所以肯定是错误的。不过看你的调试信息,就算改成这样point = (int*)*((int*)*point + 2);取到的值还是错误的。
这个内存结构没有标准,不过受影响的因素应该只是CLR与JIT的版本。
if (*point == 0) --point;
之后,你的*point(也就是你调试信息中的*0x009dc5a0)的内存数据是什么,是不是一个call 16B指令,我本地是 e8 xx xx 49 79 5e 00 00,接下来四个字节就是函数信息表的地址了。
0x009DC5C0 dc 9a 9d 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x009DC5D0 e8 e5 57 49 79 5e 00 03 e8 dd 57 49 79 5e 05 02 ..WIy^....WIy^..
0x009DC5E0 e8 d5 57 49 79 5e 0a 01 e8 cd 57 49 79 5e 0f 00 ..WIy^....WIy^..
0x009DC5F0 4c 9b 9d 00 00 00 00 00 00 00 00 00 00 00 00 00 L...............
0x009DC600 00 00 00 00 b8 60 9b 9d 00 89 ed e9 bc 58 a3 ff .....`.......X..
0x009DC610 b8 74 9b 9d 00 89 ed e9 b0 58 a3 ff b8 88 9b 9d .t.......X......
0x009DC620 00 89 ed e9 a4 58 a3 ff e8 8d 57 49 79 5e 00 02 .....X....WIy^..
反汇编结果:
xxxx:0100 E80558 CALL 5908
xxxx:0103 49 DEC CX
xxxx:0104 795E JNS Short 0164
xxxx:0106 0001 ADD [BX+DI],AL
xxxx:0108 E9CB50 JMP 51D6
其中0x009DC5B7(107)位置你是00,我的是01,这一点有差异。接下来的四个字节:e9 cb 50 8d,所以就变得0x80000000了.感觉这是有点偏了,这对程序的稳定性会不会大打折扣?
如果无法确定的话,看来应该找到那个与0x009DC5B0比较接近的值。
也就是函数第一次执行之前,函数信息表的第一个int&0x30000000=0;执行之后函数信息表的第一个int&0x30000000=0x30000000。另外函数信息表中的函数指针也会被修改而变化。
debug数据如下:
methodPoint.Point:13795c4
int* point = (int*)methodPoint.Point + 4;
point:1333b44
*point:0000
if (*point == 0) --point;
*point:9dc580
(int*)*point+4:9dc590
*((int*)*point+4):9d9adc
point = (int*)*((int*)*point + 4);
point:9d9adc
*point:4b00000e ??????
point+2:9d9ae4
*(point+2):9dc580
*(point+5):0004
*(point+18):79286a90其中问号的 *point 为 4b00000e,与8000000 与一下,就变成泛型函数了?而跳过 泛型函数的判断,让其 +2,结果又回到 9dc580 ,程序感觉上没有变化。
0x009DC580 e8 35 58 49 79 5e 00 01 e9 fb 50 8d 00 5f 04 00 .5XIy^....P.._..
0x009DC590 dc 9a 9d 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x009DC5A0 e8 15 58 49 79 5e 00 03 e8 0d 58 49 79 5e 05 02 ..XIy^....XIy^..
0x009DC5B0 e8 05 58 49 79 5e 0a 01 e8 fd 57 49 79 5e 0f 00 ..XIy^....WIy^..
0x009DC5C0 4c 9b 9d 00 00 00 00 00 00 00 00 00 00 00 00 00 L...............
==========
0x009D9ADC 0e 00 00 4b 05 00 00 00 80 c5 9d 00 00 00 00 00 ...K....€.......
0x009D9AEC 0f 00 04 3b 04 00 00 00 94 7b 8d 00 00 00 00 00 ...;.....{......
0x009D9AFC 0c 00 00 00 11 00 05 00 04 00 00 00 88 08 33 79 ..............3y
0x009D9B0C 58 8c 9d 00 34 9b 9d 00 4c 70 2c 01 00 00 00 00 X...4...Lp,.....
0x009D9B1C 00 00 00 00 70 6a 28 79 90 6a 28 79 00 6b 28 79 ....pj(y.j(y.k(y
0x009D9B2C 60 76 2f 79 88 c5 9d 00 80 00 00 00 18 5d 31 02 `v/y....€....]1.