使用泛型时,何时以及如何确定对象的类型,特别是当泛型类型被约束到一个类而泛型类型是隐式的时?
为了澄清,给出以下代码:
public class MyClass {}
public class MyClassA : MyClass {}
public static string GetMyClassTypeByGenericType<T>(T myClass)
where T: MyClass
{
return typeof(T).Name;
}
public static string GetMyClassTypeByObjectType<T>(T myClass)
where T: MyClass
{
return myClass.GetType().Name;
}
MyClassA myA = new MyClassA ();
GetMyClassTypeByGenericType(myA); // Result: "MyClassA"
GetMyClassTypeByObjectType(myA); // Result: "MyClassA"
MyClass myClass = myA;
GetMyClassTypeByGenericType(myClass); // Result: "MyClass"
GetMyClassTypeByObjectType(myClass); // Result: "MyClassA"
为什么调用GetMyClassTypeByGenericType(myClass)
返回基类的名称,而不返回派生类的名称?我猜想该调用将根据变量GetMyClassTypeByGenericType<MyClass>(myClass)
的声明类型而不是实际类型隐式地解析为myClass
。
基本上,我只想知道泛型到底是如何确定类型的。
这里是代码的小提琴:https://dotnetfiddle.net/pCj08M
答案 0 :(得分:2)
泛型类型解析全部是编译时间(这就是为什么您不能在没有反射的情况下将Type
变量填充到泛型类型参数中的原因,这实际上不是我们在这里谈论的内容)。
因此,当给定变量类型MyClassA
时,将使用它。对于MyClass
同样,即使实际对象是派生类型。例如,如果您将其保存在object
引用中,则第一个调用将显示System.Object
。
另一方面,GetType
是运行时,因此无论对象的变量类型是什么,它都会获得对象的 actual 类型。
答案 1 :(得分:1)
泛型类型构造(解析每个泛型类型参数的实际类型的过程)始终在C#的编译时执行(当然,除非您使用Reflection API在以下位置构造泛型)运行时)。
在您的示例中,编译器根据传递给方法的参数的 static 类型来推断类型T
。 myClass
的静态类型正是您声明的静态类型:MyClass
。因此,当您使用通用方法检查T
时,您会发现T == typeof(MyClass)
。
另一方面,当您对传入的对象调用.GetType()
时,您正在对对象的动态(实际运行时)类型进行运行时查询,这当然是您构造的{ {1}}。