Как создать общий метод из двух похожих, но разных методов?

у меня есть два похожих метода, которые в основном делают то же самое только с разными объектами. Каков наилучший способ сделать общий метод из этого, если это возможно?

два объекта:

public class StoreObject {
  int Key;
  string Address;
  string Country;
  int Latitude;
  int Longitude;
}

public class ProjectObject {
  int ProjectKey;
  string Address;
  string Description;
}

два метода, которые я потенциально хочу сделать в родовую:

public StoreObject GetStoreByKey(int key)
{
  using (DBEntities dbe = new DBEntities())
  {
    StoreObject so = new StoreObject();
    var storeObject = (from s in dbe.StoreTables
                       where s.Key == key
                       select s).First();

    so.Key = storeObject.key;
    so.Address = storeObject.address;
    so.Country = storeObject.country;
    so.Latitude = storeObject.latitude;
    so.Longitude = storeObject.longitude;

    return so;
  }
}

public ProjectObject GetProjectByKey(int projectKey)
{
  using (DBEntities dbe = new DBEntities())
  {
    ProjectObject po = new ProjectObject();
    var projectObject = (from p in dbe.ProjectTables
                       where p.ProjectKey == projectKey
                       select p).First();

    po.Key = projectObject.p_key;
    po.Address = projectObject.p_address;
    po.Description = projectObject.p_description;

    return po;
  }
}

Я должен отметить, что:
- У меня нет контроля над тем, как называются поля таблицы (т. е. p_description).
- StoreTable в БД, например, может иметь другие свойства (например, телефон, почтовый индекс и т. д.), Но меня интересует только то, что я показал в коде.
- То же самое касается ProjectTable.

4 ответов


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

public T GetEntityByKey<T>(int key)
{
  using (DBEntities dbe = new DBEntities())
  {
    return = dbe.StoreTables.Set<T>.Find(new object[] {key});
  }
}

и использовать его

StoreObject so  = GetEntityByKey<StoreObject>(123);
if(so != null)
{
    int lat = so.Latitude;
} 

вы действительно можете абстрагировать возвращаемый тип и разложить на множители using, но для остального вам понадобится либо переключатель запрошенного типа, либо отражение для передачи в полях для извлечения в качестве параметров и запроса DB для использования.

первое было бы плохой практикой и мало что приносит уравнению, а последнее дорого и может стать грязным.

Это не очень хороший кандидат для дженериков, если у вас много таких подобных методов, в этом случае Я бы предпочел рефлексивный подход.

HTH,

Баб.


очень маловероятно, что это вся ваша "единица работы" и, следовательно, использование свежего DBEntities() контекст в каждом из этих методов, вероятно, является корнем вашей проблемы здесь.

создание Repository класс, который содержит экземпляр DBEntities класс для одного веб-запроса (или любой другой единицы запроса, который у вас есть в вашем приложении), и который имеет эти методы в нем, был бы лучшим подходом к устранению дубликата кода здесь. Объем - это вне этих методов и, надеюсь, привязан к вашему веб-запросу или другой единице времени.

в качестве опции вместо создания нового класса вы также можете расширить DBEntities частичный класс для включения таких методов (при условии, что это сгенерированный код).


у вас по существу есть две разные функции в каждом методе:

  1. запрос субъекта
  2. сопоставьте эту сущность с другим типом

первая часть была рассмотрена Стивом Мэллори.

во второй части можно использовать структуру сопоставления для обработки копирования значений из одного экземпляра в другой. Поскольку имена каждого типа не совпадают, вам нужно рассказать ему, как сопоставить имена (в вашем примере, добавив " p_ " и сделав это нижний регистр.) Одной из возможностей было бы Выделяют Картографа.

Если вы были чтобы исключить всю общность, это было бы что-то вроде:

public TResult GetById<TResult, TEntity>(int id)
{
    using (DBEntities dbe = new DBEntities())      
    {        
        T result = dbe.StoreTables.Set<T>.Find(new object[] {key});
        var mapper = ObjectMapperManager.DefaultInstance
            .GetMapper<TEntity, TResult>(
               new DefaultMapConfig().MatchMembers((m1, m2) => "p_" + m1.ToLower() == m2));

        return mapper.Map(result);      
    }
}