4

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

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

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

3 回答 3

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)。

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

于 2012-12-26T10:29:35.317 回答
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);
于 2012-12-26T10:30:56.773 回答
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 获得

于 2012-12-26T10:52:35.960 回答