话说有一天你要用反射来对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)
...{
}
}
可以看到Foo有2个重载,唯一的区别在于第二个Foo方法签名中有带ref的参数。
如果你直接写:
Target myTarget = new Target();
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);
哎呀,扔了一个“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);
结果却返回了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);
oops,输出长度还是0!(这个地方不知道使用BindingFlags的方法对不对,还请大家指正)
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.
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)));
再看结果,呵呵,吃惊吧。以上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之间不存在什么关系哦...