C# 如何在C中获取泛型类的子类型#
我有一个通用方法C# 如何在C中获取泛型类的子类型#,c#,generics,C#,Generics,我有一个通用方法 public async Task Save<T>(T aggregate) where T : AggregateRoot var indexRegistrations = IndexRegistrar.GetAll<T>(); 但是,typeof(T)总是返回AggregateRoot 如何获得T的真实类型(AggregateRoot的子类型?您的问题有一个类似的答案: 通常typeof运算符检查编译时的已知类型。因此,在您的情况下,它将始终是
public async Task Save<T>(T aggregate) where T : AggregateRoot
var indexRegistrations = IndexRegistrar.GetAll<T>();
但是,typeof(T)
总是返回AggregateRoot
如何获得
T
的真实类型(AggregateRoot
的子类型?您的问题有一个类似的答案:
通常
typeof
运算符检查编译时的已知类型。因此,在您的情况下,它将始终是AggregateRoot
。要匹配T
本身及其所有继承者,请使用IsAssignableFrom
反射方法,而不是类型对象比较:
public static List<IndexRegistration> GetAll<T>() where T : AggregateRoot
{
return _register.FindAll(r => typeof(T).IsAssignableFrom(r.aggregateType));
}
publicstaticlist GetAll(),其中T:AggregateRoot
{
返回_register.FindAll(r=>typeof(T).IsAssignableFrom(r.aggregateType));
}
正如@Flater answer所述,typeof
在这种情况下有效,除非在实例化这些对象时您不知道它们的类型
因此,此解决方案适用于在运行时实例化的类型。如果您在编译时知道类型,它也可以工作,但是它更复杂,并且增加了复杂性
一个解决方案是能够拥有您的类型的实例,为了在该实例上调用GetType()
,这将为您提供对象的最低继承类型
因此,要获取实例,您可以更改函数并请求传递对象:
public static List<IndexRegistration> GetAll<T>(T instance) where T : AggregateRoot
{
return _register.FindAll(r => r.aggregateType == instance.GetType());
}
公共静态列表GetAll(T实例),其中T:AggregateRoot
{
返回_register.FindAll(r=>r.aggregateType==instance.GetType());
}
您可以选择,然后检索类型。这要求您将泛型类型标记为具有:
publicstaticlist GetAll()其中T:AggregateRoot,New()
{
T实例=新的T();
返回_register.FindAll(r=>r.aggregateType==instance.GetType());
}
typeof(T)
在这里是正确的。
我测试了您的案例,并且typeof(T)
总是返回“true”类,而不仅仅是类型要求
public class BaseClass { }
public class DerivedClass: BaseClass { }
public class GenericClass<T> where T : BaseClass
{
public string TypeOf = typeof(T).ToString();
}
public class GenericSuperClass<T> where T : BaseClass
{
public GenericClass<T> Sub = new GenericClass<T>();
}
static void Main(string[] args)
{
Console.WriteLine("1 - " + (new GenericClass<BaseClass>()).TypeOf);
Console.WriteLine("2 - " + (new GenericClass<DerivedClass>()).TypeOf);
Console.WriteLine("3 - " + (new GenericSuperClass<BaseClass>()).Sub.TypeOf);
Console.WriteLine("4 - " + (new GenericSuperClass<DerivedClass>()).Sub.TypeOf);
Console.ReadLine();
}
注意,我已经根据实际返回的值简化了类名(例如Sandbox.TestConsole.Program+DerivedClass
)
这直接反驳了您的说法,即您只能获得基类型(AggregateRoot
,在您的情况下)
反射是一个例外。 我可以想到一个例外:当您的类型仅在运行时定义时(例如,从类型名(
String
)生成)。然而,正如所解释的,泛型旨在提供编译时的类型安全性 在运行时使用反射实例化泛型类并非不可能。但是当您这样做时,您本质上是在阻止编译时决定的信息(例如类型名)的有效性。
隐式声明
typeof
的返回值是编译时类型
结合这两个事实,这意味着当您使用反射(即在运行时决定类型)时,您不能依赖typeof
(因为这将返回编译时类型)
链接的MSDN页面还提到如何查找运行时类型: 要获取表达式的运行时类型,可以使用.NET Framework方法GetType,如下例所示:
int i = 0;
System.Type type = i.GetType();
但是,请注意,GetType()
方法仅适用于实例化的对象,而不适用于泛型类型参数。泛型类型参数不是真正的类型,它们更接近“类型占位符”
您需要将类型作为参数传递,或者将实例化对象(适当类型)传递
结论: 如果您使用的是编译时已知的类型,那么您可以简单地使用
typeof(T)
,如我的示例所示
如果使用反射在运行时决定类型,则不能依赖typeof(T)
提供的信息,因此需要提供类型。可以将其作为类型
参数提供,也可以通过实例化对象提供,该对象的运行时类型可以使用GetType()
方法进行准确测试
但是,如果您已经在运行时决定了类型,那么最好将类型本身作为参数传递。如果您在这里使用反射,这意味着您必须在某个时候知道要使用哪种类型。因此,只需将该已知类型作为参数传递,然后就可以将其用于后续业务逻辑
我想不出有哪一种场景是这样的:(a)使用编译时已知的类型,或者(b)不知道(在运行时)决定使用的类型。GetType应该这样做。问题是,您应该将该类型的对象传递给方法本身,这样您就可以对其调用
GetType
。任何其他调用,例如typeof(T)
将返回编译时类型,这与您的情况无关。@YairHalberstadt如何获取类型“do it”?在这里尝试过,如果我发送子类型,它总是使用子类型。在将对象传递到Save()
方法之前,您是否将其强制转换为AggregateRoot
?因为T==AggregateRoot@CptSlow将GetAll更改为GetAll(类型searchType)
?然后您可以传递运行时类型…请注意,IsAssignableFrom
在某些情况下可能会给出令人惊讶的结果。例如,一个IEnumerable
类型的变量可以被分配一个List
类型的对象,即使List
实现了IEnumerable
,而不是IEnumerable
。我怀疑这是一个解决方案,因为我怀疑所有r
都符合此检查。T必须已经是运行时类型,而不是AggregateRoot。不,这是不正确的<代码>类型(T)其中public class BaseClass { }
public class DerivedClass: BaseClass { }
public class GenericClass<T> where T : BaseClass
{
public string TypeOf = typeof(T).ToString();
}
public class GenericSuperClass<T> where T : BaseClass
{
public GenericClass<T> Sub = new GenericClass<T>();
}
static void Main(string[] args)
{
Console.WriteLine("1 - " + (new GenericClass<BaseClass>()).TypeOf);
Console.WriteLine("2 - " + (new GenericClass<DerivedClass>()).TypeOf);
Console.WriteLine("3 - " + (new GenericSuperClass<BaseClass>()).Sub.TypeOf);
Console.WriteLine("4 - " + (new GenericSuperClass<DerivedClass>()).Sub.TypeOf);
Console.ReadLine();
}
1 - BaseClass
2 - DerivedClass
3 - BaseClass
4 - DerivedClass
int i = 0;
System.Type type = i.GetType();