话说有一天你要用反射来对Target类进行操作,调用Foo函数。
public class Target
...{
public void Foo(int x, int y, int z)
...{
}
public void Foo(int x, ref int y, out int z)
...{
}
}
...{
public void Foo(int x, int y, int z)
...{
}
public void Foo(int x, ref int y, out int z)
...{
}
}
可以看到Foo有2个重载,唯一的区别在于第二个Foo方法签名中有带ref的参数。
如果你直接写:
Target myTarget = new Target();
Type t = myTarget.GetType();
MethodInfo methodInfoWithRefParamters = t.GetMethod("Foo");
Type t = myTarget.GetType();
MethodInfo methodInfoWithRefParamters = t.GetMethod("Foo");
那么会在RunTime扔个Exception说: Ambiguous match found.
要想invoke第二个Foo的话,我们必须这样写:
MethodInfo methodInfoWithRefParamters = t.GetMethod("Foo", new Type[] ...{typeof(int), Type.GetType("System.Int32&"),Type.GetType("System.Int32&") });
好吧,现在运行是正常运行了,可是新的问题又来了:这个System.Int32&是个啥东东呢?
先在MSDN/
.Net Reflector
找找Int32&,没有。Google和查看微软放出的Framework Source Code,同样无果。
得,现成的资料找不到,那只有让我们自己通过做试验来玩玩了。
1。 先试试能不能搞一个Int32&的实例出来:
当然,就不用指望直接能在C#里面new一个Int32&了。(如果是unsafe的话,Int32*到还可以)
来试试亲爱的Activator吧:
当然,就不用指望直接能在C#里面new一个Int32&了。(如果是unsafe的话,Int32*到还可以)
来试试亲爱的Activator吧:
Type refInt32Type = Type.GetType("System.Int32&");
object myRefInt = System.Activator.CreateInstance(refInt32Type, true);
object myRefInt = System.Activator.CreateInstance(refInt32Type, true);
哎呀,扔了一个“No parameterless constructor defined for this object.”异常出来。
2。好吧,那让我们来看看Int32&有啥样的constructor:
BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.NonPublic ;
Console.WriteLine(refInt32Type.GetConstructors(bf).Length);
Console.WriteLine(refInt32Type.GetConstructors(bf).Length);
结果却返回了0。
狠一点,把全部BindingFlags Enum放到bf上去呢,用GetMembers试试呢?
BindingFlags bf = // all values of BindingFlags
Console.WriteLine("count of member in type Int32&: {0}", Type.GetType("System.Int32&").GetMembers(bf).Length);
Console.WriteLine("count of member in type Int32&: {0}", Type.GetType("System.Int32&").GetMembers(bf).Length);
3。Ok,Ok,不能创建实例就暂时不管它,那让我们用QuickWatch来看看这个Int32&类型有啥属性:
下面是我把Int32,Int32&, Int32*,外加Boolean&类型做对比的结果。(属性值相同的已经略过)
Int32
|
Int32&
|
Int32*
|
Boolean&
| |
Attributes
|
1057033
|
NotPublic
|
NotPublic
|
NotPublic
|
BaseType
|
{"System.ValueType"}
|
《undefined value》
|
《undefined value》
| 《undefined value》 |
FullName
|
System.Int32
|
System.Int32&
|
System.Int32*
|
System.Boolean&
|
GUID
|
a310fadd-7c33-377c-9d6b-599b0317d7f2
|
全是0
|
全是0
|
全是0
|
HasElementType
|
false
|
true
|
true
|
true
|
IsAutoLayout
|
false
|
true
|
true
|
true
|
IsByRef
|
false
|
true
|
true
|
true
|
IsClass
|
false
|
true
|
true
|
true
|
IsLayoutSequential
|
true
|
false
|
false
|
false
|
IsNotPublic
|
false
|
true
|
true
|
true
|
IsPointer
|
false
|
false
|
true
|
false
|
IsPrimitive
|
true
|
false
|
false
|
false
|
IsPublic
|
true
|
false
|
false
|
false
|
IsSealed
|
true
|
false
|
false
|
false
|
IsSerializable
|
true
|
false
|
false
|
false
|
IsValueType
|
true
|
false
|
false
|
false
|
通过这张表我们可以观察到很有意思的结果:
Int32& 是ByRef的(最明显,呵呵),不是ValueType, 不可以序列化,没有Sealed,GUID都是0,BaseType 显示为《undefined value》
Int32& 是ByRef的(最明显,呵呵),不是ValueType, 不可以序列化,没有Sealed,GUID都是0,BaseType 显示为《undefined value》
请特别注意的是Int32&, Int32*它们IsClass属性为True,说明是个Class,先记下来,在后面我会给大家看一个更有趣的结果。
既然,Int32&和Int32*都说自己有ElementType,那就来看看是什么Type吧:
Type.GetType("System.Int32&").GetElementType(); // Print “System.Int32”
Type.GetType("System.Int32*").GetElementType(); // Print “System.Int32” too.
Type.GetType("System.Int32*").GetElementType(); // Print “System.Int32” too.
4.回过头来看看生成的IL代码呢?
如图,只能看到对于ref/out 的参数,使用的是ldloca.s 指令,还是没看到我们的Int32&类型,
5.最后来看看最有趣的发现:
先试试在你的机器上run这3句代码:
先试试在你的机器上run这3句代码:
Console.WriteLine(Type.GetType("System.Int32&").IsSubclassOf(typeof(object)));
Console.WriteLine(Type.GetType("System.Int32*").IsSubclassOf(typeof(object)));
Console.WriteLine(Type.GetType("System.Boolean*").IsSubclassOf(typeof(object)));
Console.WriteLine(Type.GetType("System.Int32*").IsSubclassOf(typeof(object)));
Console.WriteLine(Type.GetType("System.Boolean*").IsSubclassOf(typeof(object)));
再看结果,呵呵,吃惊吧。以上3句都是输出False。难道说.Net里存在着不是从Object继承的Type吗?可它的IsClass属性是为True的哦~
会不会Int32&不是属于.Net框架的呢?可看看它的AssemblyQualifiedName是“System.Int32&, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”,也没看出什么问题啊?(汗)
2005/08/16 Update:
ByRef types 是受控指针,在CLR里面也是真实存在的类型。不过因为只有很少的IL指令能够作用与它,所以我们不能创建它的实例。同时,系统也限制我们只能在parameter的位置使用ByRef的类型。值得注意的是Int32&和Int32之间不存在什么关系哦...