2012-04-09 17 views
7

Mam dwie podobne metody, które w zasadzie robi to samo tylko z różnymi obiektami. Jaki jest najlepszy sposób, aby w miarę możliwości zastosować ogólną metodę?Jak stworzyć ogólną metodę z dwóch podobnych, ale różnych metod?

dwóch obiektów:

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

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

dwóch metod, że potencjalnie chcą przekształcić ogólna:

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

muszę zauważyć, że:
- nie mam kontroli nad sposób nazywania nazw pól (np. p_description).
- Na przykład StoreTable w DB może mieć inne właściwości (takie jak telefon, kod pocztowy, itp.), Ale interesuje mnie tylko pokazanie tego, co pokazałem w kodzie.
- To samo dotyczy ProjectTable.

+1

Metody te nie są podobne. Niemal każda linia jest inna. Można wprowadzić wyrażenie jako klauzulę where, ale to tylko sprawi, że rzeczy będą bardziej złożone. Każda z tych metod dokładnie wie, jak traktować obiekt, którym się zajmują. Wydaje mi się, że jest tak abstrakcyjny, jak to tylko możliwe. –

+0

No cóż, będę musiał twierdzić, że są podobieństwa i chociaż zgadzam się, że jest już abstrahowany, pomyślałem, że spróbuję zapytać, na wypadek, gdyby inni ludzie wpadli na pomysł, aby uczynić go jeszcze bardziej. – kei

Odpowiedz

3

Cóż, najtrudniejszą częścią jest to, że twoje obiekty mają różne właściwości, więc użycie generycznych do wypełnienia różnych właściwości w ramach jednej metody nie będzie tego warte. Ale możesz zwrócić cały obiekt, a następnie po prostu użyć właściwości, które Cię interesują.

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

I go używać

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

Doceniam wkład każdego, ale będę musiał odpowiedzieć na pytanie Steve'a. (Będę musiał zmienić niektóre rzeczy, ponieważ nie tylko dostaję rzeczy z StoreTables) – kei

2

Rzeczywiście można pominąć zwracany typ i współczynnik using, ale do reszty potrzebny jest przełącznik na żądany typ lub odbicie do przekazania w polach do pobrania jako parametry i zapytanie do bazy danych do posługiwać się.

Pierwsza z nich byłaby złą praktyką i nie przynosiła wiele do równania, a ta druga jest kosztowna i może stać się nieporządna.

To naprawdę nie jest dobry kandydat na leki generyczne, chyba że masz wiele takich podobnych metod, w którym to przypadku wybrałbym metodę refleksji.

HTH,

Bab.

+0

Rozważyłem refleksję, ale pomyślałem, że spróbuję sprawdzić, czy można to zrobić jako rodzajowy. – kei

2

Jest bardzo mało prawdopodobne, że jest to cała Twoja "jednostka pracy", a zatem użycie świeżego kontekstu DBEntities() w każdej z tych metod jest prawdopodobnie źródłem twojego problemu tutaj.

Tworzenie klasy Repository który zawiera instancję klasy DBEntities dla pojedynczego żądania sieci (lub cokolwiek inna jednostka żądanie masz w swojej aplikacji) i który ma te metody w niej byłoby lepsze podejście do wyeliminowania duplikat tutaj kod. Zakres using() jest poza tymi metodami i, mam nadzieję, jest powiązany z twoją prośbą sieciową lub inną jednostką czasu.

Jako opcja zamiast tworzenia nowej klasy można również rozszerzyć klasę cząstkową o DBEntities, aby uwzględnić takie metody (zakładając, że jest to wygenerowany kod).

+0

Dobry pomysł, ale nadal chcę spróbować przekształcić je w rodzajowy. – kei

2

You mają zasadniczo dwie różne funkcje w każdej z metod:

  1. zapytania jednostka
  2. mapę, która jednostka do innego rodzaju

Th Pierwsza część została podjęta przez Steve Mallory.

Dla drugiej części można użyć struktury odwzorowania do obsługi kopiowania wartości z jednej instancji do drugiej. Ponieważ nazwy poszczególnych typów nie pasują do siebie, musisz powiedzieć im, jak mapować nazwy (w twoim przykładzie, dodając "p_" i robiąc małe litery). Jedną z możliwości byłby Emit Mapper.

Jeśli były czynnik poza wspólność wszystko, to byłoby coś takiego:

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);  
    } 
} 
+0

Hmmm .. Rozważę to, ale może być prostsze odwzorowanie trzech pól ręcznie. – kei

Powiązane problemy