简体   繁体   中英

Cast of generic property through reflection

I'm trying to retrieving a DbContext DbSet property by its name but I don't know how to handle the generic parameter.

DataSource.Load(IQuerable source) method comes from an external dll and I cannot modify it.

Knowing the property name of my DbSet prop (from an entity framework dbcontext class) I want to use that property value as parameter for DataSource.Load

 public class DataManager
 {

    private MyDbContext _dbContext;

    public DataManager(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }


    public object Load(string propName)
    {
        var source = _dbContext.GetType().GetProperty(entityName).GetValue(_dbContext, null);

        return DataSourceLoader.Load(source);         
    }

    //DataSourceLoader.Load signature:
    //DataSourceLoader.Load<T>(System.Linq.IQueryable<T>)

Update

To be more clear: DataSourceLoader.Load loads data from an entity set; I don't care of the return type because it will be serialized and sent to a client plugin.

A client plugin requests the data by an ajax call using the entitySet name as parameter. I don't want to have a different method (or a long switch statement) for each entity set I have and statically invoke the DataSource.Load method.

I would like to resolve the entity set to query at runtime

The way I understand it, the question is how to call a generic method at runtime.

It's possible to do that with reflection by obtaining the generic MethodInfo definition, binding the generic arguments via MakeGenericMethod call and invoking it via Invoke method.

The concrete answer depends on many factors like if the method is static or instance, if the name is unique or not (overloads) etc. You can see more details about that in Select Right Generic Method with Reflection , but in the simplest form it would be something like this:

var elementType = ((IQueryable)source).ElementType;
var loadMethod = typeof(DataSourceLoader).GetMethod("Load")
    .MakeGenericMethod(elementType);
return loadMethod.Invoke(null, new object[] { source });

You can avoid all that complications by utilizing the DLR Fast Dynamic Dispatch and Invocation feature. All you need in this case is a simple cast to dynamic :

return DataSourceLoader.Load((dynamic)source);

You could try with this method:

public object Load(string setName)
{
    var property = _context.GetType().GetProperties()
        .SingleOrDefault(p => p.PropertyType.IsGenericType
                      && p.PropertyType.GetGenericArguments()[0].GetProperty(setName) != null);
    return property.GetValue(_context) ?? throw new ArgumentOutOfRangeException(setName);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM