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

时间:2012-12-26 10:19:37

标签: c# .net generics generic-method

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

IPersister GetPersisterFor(IEntity entity)
{
    return GetPersisterFor<entity.GetType()>(); // <-- this cannot be compiled
}

IPersister GetPersisterFor<TEntity>() where TEntity : IEntity
{
    //some logic to get persister...
}

3 个答案:

答案 0 :(得分:4)

只能通过反思;您需要使用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)。

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

答案 1 :(得分:1)

是的,您需要获取通用方法定义。 之后,您可以使用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);

答案 2 :(得分:1)

因为泛型和非泛型方法都具有相同的名称,所以必须迭代所有类的方法以找到合适的方法,然后调用它:

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

提供的完整源代码