Question

Can I use a type from reflection as a type parameter? E.g. I want to pick a persister based on a passed object:

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

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

Solution

Only via reflection; you would need to use GetMethod to get the MethodInfo for the generic method, then call MakeGenericMethod(entity.GetType()).Invoke(this, null); on that.

However, easier is to cheat via dynamic:

IPersister Evil<T>(T obj) where T : IEntity {
    return GetPersisterFor<T>();
}

And make the first method just:

return Evil((dynamic)entity);

This is then a dynamic expression which will detect the correct T to use (to call Evil-of-T) for you.

Note: the only reason you need an extra method is to make sure it doesn't resolve back to itself recursively, since the names are the same.

OTHER TIPS

Yes, you need to get the generic method definition. After that you can use MethodInfo.MakeGenericMethod to construct the generic method.

So something like:

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

Because both generic and non generic methods have same name, you have to iterate over all methods of class to find proper one, and then invoke it:

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: full source code available at gist.github

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top