Pytanie w sprawie c#, generics, inheritance – Wywołanie metody ogólnej z poprawnym typem pochodnym

9

Mam następujący scenariusz:

Mam trzy klasy, nazwijmy jeA, B iC. Jedyne co ich łączy to dziedziczenie z tego samego interfejsu,ISomeInterface i że są to klasy odwzorowane na jednostki używające Entity Framework.

Mam metodę, która otrzymała listę obiektów implementujących ten interfejs, ale same obiekty będą instancjamiA, B lubC.

Powłoka metody wygląda tak

public void MyMethod(List<ISomeInterface> entityList)
{
  foreach(var entity in entityList)
  {
    ProcessEntity(entity);
  }
}

Teraz problem jest zProcessEntity metoda. Jest to ogólna metoda, która musi pobrać tabelę pasujących elementów z bazy danych zgodnie z typem lub jednostką, więc wygląda to tak:

public void ProcessEntity<T>(T entity)
{
  using( var repository = new DbRepository())
  {
    var set = repository.Set<T>();
    ...
  }
}

Problem polega na tym, że liniavar set = repository.Set<T>(); zawodzi, ponieważT jestISomeInterface w tym przypadku, a nie rzeczywisty typ (A, B lubC), więc daje wyjątek, który nie może odnosić się do danego typu, co jest zrozumiałe.

Moje pytanie brzmi: jak mogę wywołać ProcessEntity z rzeczywistym typem obiektu na liście, a nie z wprowadzonym przez niego typem interfacetype.

Twoja odpowiedź

3   odpowiedź
2

możesz zrobić sztuczkę podobną do gościa i użyć następującego obejścia:

Zdefiniuj metodęProcess(EntityProcessor ep) wISomeInterfaceZaimplementuj goA tak jakep.ProcessEntity<A>(this) (i tak samo wB iC)ZamiastProcessEntity(entity) w pętli po prostu zadzwońentity.Process(this).

(nazwy metod nie są chyba najczystsze, ale powinieneś mieć pomysł)

@ Øyvind: w moim przykładzie dodana jest nowa funkcjaISomeInterface (co jest rzeczywiście rodzajem wsparcia dla gości). W ten sposób każdyentity musi go wdrożyć, jak to ma miejsceISomeInterface. Vlad
To by działało, ale odpowiedź lazyberezovsky'ego jest dla mnie znacznie czystsza, ponieważ oznacza to, że nie muszę wprowadzać większej logiki do A, B i C (i jest ostro jak 20 takich typów, a nie 3;) Øyvind Bråthen
Widzę twój punkt widzenia, ale używając dynamiki nie masz w ogóle potrzebnej metody, a ja wolałbym, aby klasy A, B i C nie miały żadnej wiedzy na temat tej funkcji. Oznacza to również, że nie muszę pamiętać o umieszczeniu tej dodatkowej funkcjonalności dla nowych utworzonych klas, które mają być zgodne z tym samym wzorcem. Øyvind Bråthen
Tak, a tego właśnie unikam, używając dynamiki. Tak więc kompromis w tym przypadku jest utratą pewnego bezpieczeństwa typu (i jest w tym przypadku w porządku, ponieważ jest to tylko jedna metoda), aby utrzymać moduł czyszczący uprawnień przez nie wymuszanie na nich jakiejś metody interfejsu, która musi być zaimplementowana przez wszyscy. Øyvind Bråthen
2

aby uzyskać ogólną definicję metody, a następnie nazwać ją, np .:

var method = typeof(ClassContainingProcessEntity)
    .GetMethod(ProcessEntity)
    .MakeGenericMethod(entity.GetType);
method.Invoke(this, entity);

Metodę można buforować według typu i można ją skompilować w czasie wykonywania za pomocą jakiejś fabryki delegatów, jeśli wydajność jest krytyczna.

Alternatywnie możesz użyćWzór gościa

Tak, oba powinny działać, a ja myślałem o przejściu przez drogę refleksji, jeśli nie dostanę tutaj lepszej odpowiedzi. Wygląda na to, że to dynamiczne, ale znacznie czystsze. Dzięki za wkład :) Øyvind Bråthen
14

Możesz aplikowaćdynamic słowo kluczowe podczas przekazywania podmiotu do ProcessEntity. W tym przypadku rzeczywisty typ obiektu zostanie określony w czasie wykonywania.

public void MyMethod(List<ISomeInterface> entityList)
{
  foreach(var entity in entityList)
  {
    dynamic obj = entity;
    ProcessEntity(obj);
  }
}
@ ØyvindKnobloch-Bråthen yep, bardzo lubię tę typizację w czasie wykonywania Sergey Berezovskiy
To załatwiło sprawę. zmieniamProcessEntity(obj); doProcessEntity(obj as dynamic);, i to działało dobrze. Zastosowanie dynamiki, o której nie wiedziałem. Wielkie dzięki :) Øyvind Bråthen

Powiązane pytania