我可以使用来自反射的类型作为类型参数吗?

本文关键字:类型参数 类型 反射的 可以使 我可以 | 更新日期: 2023-09-27 17:49:28

可以使用来自反射的类型作为类型参数吗?例:我想根据传递的对象选择一个持久性对象:

IPersister GetPersisterFor(IEntity entity)
{
    return GetPersisterFor<entity.GetType()>(); // <-- this cannot be compiled
}
IPersister GetPersisterFor<TEntity>() where TEntity : IEntity
{
    //some logic to get persister...
}

我可以使用来自反射的类型作为类型参数吗?

只能通过反射;您需要使用GetMethod来获取通用方法的MethodInfo,然后在其上调用MakeGenericMethod(entity.GetType()).Invoke(this, null);

然而,通过动态: 更容易作弊。
IPersister Evil<T>(T obj) where T : IEntity {
    return GetPersisterFor<T>();
}

让第一个方法变成:

return Evil((dynamic)entity);

这是一个动态表达式,它将为您检测要使用的正确T(调用Evil-of-T)。

注意:你需要一个额外的方法的唯一原因是确保它不会递归地解析回自己,因为名字是相同的。

是的,您需要获得泛型方法定义。之后,您可以使用MethodInfo.MakeGenericMethod来构造泛型方法。

比如:

MethodInfo genericMethodDefinition = GetType()
    .GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
    .Where(method => method.IsGenericMethod && method.Name == "GetPersisterFor")
    .First();
// OR
MethodInfo genericMethodDefinition = GetType().GetMethod("GetPersisterFor",
    BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
// THEN
MethodInfo genericMethod = genericMethodDefinition.MakeGenericMethod(entity.GetType());
genericMethod.Invoke(this, null);

由于泛型和非泛型方法具有相同的名称,因此您必须遍历类的所有方法以找到合适的方法,然后调用它:

public IPersister GetPersisterFor(IEntity entity)
{       
    MethodInfo getPersisterForGenericMethod = 
                    GetType().GetMethods()
                        // iterate over all methods to find proper generic implementation
                        .Single(methodInfo => methodInfo.Name == "GetPersisterFor" && methodInfo.IsGenericMethod)
                        // supply it with generic type parameter
                        .MakeGenericMethod(entity.GetType());
    // invoke it
    return getPersisterForGenericMethod.Invoke(this, null) as IPersister;
}
public IPersister GetPersisterFor<TEntity>() where TEntity : IEntity
{
    return null;
}

ps:完整的源代码在gist.github