在C#里面对于委托的如何加载非静态方法一直都很疑惑,自己对于非静态方法的认识来看,如果要安全的实现非静态方法必须引用实例里面的
字段,经过查阅资料,知道委托类里面有一个_target字段如果是委托的是静态方法值为零,如果委托是非静态为会自动寻找方法的实例,
说的很模糊,这个_target字段应该是一个object型,但是里面地址指向的什么。我先在程序上声明一个类有两个字段这两个字段一个为static
一个非static,有两个方法一个静态一个非静态,我在方法里面对类的方法进行操作,看看对实例有什么影响。
public delegate void testChangeDelegate(); public class testChange { public int notStaticInt; public static int staticInt; public static void staticinWay() { textStruct tt = new textStruct(); Console.WriteLine("静态方法之前{0}", staticInt); staticInt += 1; Console.WriteLine("静态方法之后{0}", staticInt); } public void notStaticWay() { textStruct tt = new textStruct(); Console.WriteLine("非静态方法之前{0}", notStaticInt); notStaticInt += 1; Console.WriteLine("非静态方法之后{0}", notStaticInt); } }
然后再main函数里面写下
static void Main(string[] args) { //委托的方法使用会改变原有实例的值测验 testChange tt = new testChange(); testChangeDelegate ttc = new testChangeDelegate(tt.notStaticWay); ttc += tt.notStaticWay; ttc += testChange.staticinWay; ttc += testChange.staticinWay; ttc(); Console.WriteLine(tt.notStaticInt); Console.WriteLine(testChange.staticInt); }
输出结果为
静态方法之前0 静态方法之后1 静态方法之前1 静态方法之后2 非静态方法之前0 非静态方法之后1 非静态方法之前1 非静态方法之后2 非静态字段为2 静态字段为2
从结果看如果是非静态方法,_target中的实例就是原来声明类中的实例
但是当我将类声明成struct时(就是将public class testChange改成 public struct testChange),我再次运行程序。
输出结果为
非静态方法之前0
非静态方法之后1
非静态方法之前0
非静态方法之后1
静态方法之前0
静态方法之后1
静态方法之前1
静态方法之后2
非静态字段为0
静态字段为2
同一个结构实例可是实例字段并没有被非静态方法改变,只是在运行时改变了,看来_target中的实例地址并不是原来struct tt的,
应该是将tt复制后,然后装箱成object将t地址赋给_target,但是复制有三种情况一种是浅层复制,一种是深层复制,一种是普通复制
直接将地址赋过去,会是哪种呢?(关于浅层复制和深层复制参照······)
首先思考上面的结果如果是深层复制上面无论是类还是结构结果都一样,现在就是判断是直接赋原对象地址的普通复制还是浅层复制
于是我修改testChange类将其修改成这样,我在类中添加了一个结构体,如果是普通复制结构体前后的静态字段和非静态字段与外面的类相同,如果是浅层
复制的话结构体里面的结果同上面结构testChange相同
public delegate void testChangeDelegate(); public class testChange { public int notStaticInt; public static int staticInt; public struct textStruct { public int notStaticInt; public static int staticInt; } public static void staticinWay() { textStruct tt = new textStruct(); Console.WriteLine("方法之前{0} {1}", staticInt,tt.notStaticInt); staticInt += 1; tt.notStaticInt += 1; Console.WriteLine("方法之后{0} {1}", staticInt, tt.notStaticInt); } public void notStaticWay() { textStruct tt = new textStruct(); Console.WriteLine("方法之前{0} {1}", notStaticInt,tt.notStaticInt); notStaticInt += 1; tt.notStaticInt += 1; Console.WriteLine("方法之后{0} {1}", notStaticInt, tt.notStaticInt); } } } testChange tt = new testChange(); testChangeDelegate ttc = new testChangeDelegate(tt.notStaticWay); ttc += tt.notStaticWay; ttc += testChange.staticinWay; ttc += testChange.staticinWay; ttc(); Console.WriteLine(tt.notStaticInt); Console.WriteLine(testChange.staticInt); Console.WriteLine(tt.tt.notStaticInt); Console.WriteLine(testChange.textStruct.staticInt);
结果是
方法之前0 1 方法之后1 1 方法之前1 0 方法之后2 1 方法之前0 0 方法之后1 1 方法之前1 1 方法之后2 2 2 2 0 2
将类改成结构后
结果是
方法之前0 1 方法之后1 1 方法之前0 0 方法之后1 1 方法之前0 0 方法之后1 1 方法之前1 1 方法之后2 2 0 2 0 2
从结果看结构体tt的结果同上面结构体testChange相同,分析可知是浅层复制。
这样看来.net framework在后台给实例方法复制对象时采用的是浅层复制,而不是直接引用地址。