2016-12-27 17 views
1

Я реализовал общий шаблон репозитория и unitofwork. Я использовал базовые шаблоны, и они отлично работают. В проекте у меня есть требование, которое гласит: каждая таблица имеет несколько полей, которые содержат длинный, очень длинный текст, и пользователь должен иметь возможность выбирать и открывать любой из них. Поскольку каждое поле называлось по-разному, я решил использовать power ov generics с отражением, чтобы написать метод, который уменьшает имя таблицы и имя поля и возвращает его. метод, в обобщенном классе Repository, я написал, как выглядит это, кажется, работает правильноВызвать метод из базового класса с использованием отражения

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 классы модели для таблиц с помощью EF. Некоторые таблицы связывают напрямую genric-репозиторий, в то время как другие имеют отдельный интерфейс и его реализацию, поскольку они требуют дополнительного метода. Пример:

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

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

И UOW реализация:

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

У меня есть вопрос о вызове метода GetPropertyByName() в бизнес-уровне. Я попытался это:

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

Который возвращает System.Reflection.TargetException. Насколько я понял, проблема заключается в реализации единицы исполнения. В моем методе вызова «prop» - это тип интерфейса (ICompanyRepo), но целью invoke должен быть класс реализации интерфейса, в данном случае «CompanyRepo». Я не мог найти, как определить тип класса реализации, и решить эту проблему. Любая помощь присваивается

+1

Сторона примечания: «Общий метод» имеет очень специфический смысл в C# - код, показанный в сообщении, не показывает никаких общих методов - пожалуйста, отредактируйте сообщение, чтобы показать реальный общий (например, 'Foo ()') или использовать другое слово ... –

+0

Метод находится внутри общего класса, репозиторий , поэтому я подумал, что правильно также вызвать метод generic. Anywat вы правы, отредактировал ту часть вопроса @AlexeiLevenkov –

+1

Я вижу. Пожалуйста, ознакомьтесь с инструкциями [MCVE] по отправке кода. Невозможно узнать, является ли тип «TEntity» конкретным (со странным соглашением об именах) или параметром родового типа на основе кода, предоставленного в сообщении. –

ответ

0

Я не уверен, что это лучший вариант, но проблема решена с использованием расширения ToExpando(), указанного here. С помощью этого расширения я мог бы забросить все свойства unitofwork и найти требуемое свойство по его названию.

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

Теперь метод используется правильно. Может быть, есть более чистое решение, и я все еще надеюсь найти это. На данный момент я собираюсь использовать это решение и просто понял, что я должен много читать и много разбираться в размышлениях, динамике и дженериках. PS Особая благодарность Alexei за важные примечания и советы