Invoke method from base class using reflection

742 Views Asked by At

I implemented generic repository pattern and unitofwork. I used basic patterns and they work great. In project I have requirement which says, every table has several fields which contains long, really long text, and user should have ability chose and open any of it. As each field named differently i decided to use power ov generics with reflection, to write method which resieves table name and field name and returns it. Method, in generic Repository class, i wrote looks like this, it seems work properly

    public interface IRepository<T> where T : class
    {
        //other methods

        string GetPropertyByName(int id, string property);
    }

    public class Repository<T> : IRepository<T> where T : class
    {
        // other methods. add, edit, delete...

        public string GetPropertyByName(int id, string property)
        {
           T model =  this.Get(id);          
           var obj = model.GetType().GetProperty(property).GetValue(model, null);
           return obj != null ?  obj.ToString() : null;
        }
    }

I creted model classes for tables with help EF. Some tables binds directly genric repository, while other have separate interface and its implementation, as they require additional method. Example:

public interface ICompanyRepo : IRepository<COMPANY>
{
    //some methods
}

public class CompanyRepo : Repository<COMPANY>, ICompanyRepo
{
    //implementations of interface methods
}

And UOW implementation:

public interface IUnitOfWork
{
    ICompanyRepo Company { get; }        
    IRepository<CURRENCY> Currency { get; }        
}

public class UnitOfWork : IUnitOfWork
{
    static DBEntities _context;
    private UZMEDEXPORTEntities context
    {
        get
        {
            if (_context == null)
                _context = new DBEntities();
            return _context;
        }
    }
    public UnitOfWork()
    {
        _context = context;
        Company = new SP_CompanyRepo();
        Currency = new Repository<CURRENCY>();

    }

    public ICompanyRepo Company { get; private set; }
    public IRepository<CURRENCY> Currency { get; private set; } 
}

I have problem on invoking GetPropertyByName() method in business layer. I tried this:

public string GetHistory(string tableName, string fieldName, int id)
    {
        var prop = unitOfWork.GetType().GetProperty(tableName);
        MethodInfo method;
        method = prop.PropertyType.GetMethod("GetPropertyByName"); //try to find method
        if(method == null) //if method not found search for interface which contains that method
           method = prop.PropertyType.GetInterface("IRepository`1").GetMethod("GetPropertyByName");
        var res = method.Invoke(prop, new object[] { id, fieldName });
        return (string)res;
    }

Which returns System.Reflection.TargetException. As I understood the problem is whith unitofwork implementation. In my invoke method "prop" is type of interface (ICompanyRepo), but invoke's target should be interface implementation class, in this case "CompanyRepo". I could not find how to identify type of implementetion class, and solve this problem. Any help is appropriated

1

There are 1 best solutions below

0
On

I am not sure that this is best option, but problem solved with use of ToExpando() extension given here. With this extension i could loop throw all properties of unitofwork and find required property by its name.

var propValue = unitOfWork.ToExpando().Single(x => x.Key == prop.Name).Value;
var res = method.Invoke(propValue, new object[] { id, fieldName });

Now method is invoking properly. May be there is cleaner solution, and I still hope to find this. For now i am going to use this solution, and just realised that I must read and practice a lot about reflections, dynamics and generics. P.S Special thanks to Alexei for important notes and advices