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();