2009-07-21 9 views
36

Aby skrócić długą historię, mam funkcję C#, która wykonuje zadanie na danym typie, który jest przekazywany jako instancja obiektu. Wszystko działa poprawnie, gdy instancja klasy jest przekazywana. Jednak, gdy obiekt jest zadeklarowany jako interfejs, chciałbym znaleźć konkretną klasę i wykonać działanie na tym typie klasy.Znajdowanie typu betonu za instancją interfejsu

Oto wszechobecne zły przykład (olśniewający z niepoprawny nieruchomości obudowy itp):

public interface IA 
{ 
    int a { get; set; } 
} 
public class B : IA 
{ 
    public int a { get; set; } 
    public int b { get; set; } 
} 
public class C : IA 
{ 
    public int a { get; set; } 
    public int c { get; set; } 
} 

// snip 

IA myBObject = new B(); 
PerformAction(myBObject); 

IA myCObject = new C(); 
PerformAction(myCObject); 

// snip 

void PerformAction(object myObject) 
{ 
    Type objectType = myObject.GetType(); // Here is where I get typeof(IA) 
    if (objectType.IsInterface) 
    { 
     // I want to determine the actual Concrete Type, i.e. either B or C 
     // objectType = DetermineConcreteType(objectType); 
    } 
    // snip - other actions on objectType 
} 

Chciałbym kod w PerformAction używać refleksji na to parametr i widzę, że to nie tylko wystąpienie AF ale to jest instancja klasy B i zobaczenie właściwości "b" za pomocą metody GetProperties(). Jeśli używam metody .GetType(), otrzymuję typ IA - nie to, czego chcę.

W jaki sposób PerformAction może określić bazowy typ betonu instancji IA?

Niektórzy mogą chcieć zasugerować użycie klasy abstrakcyjnej, ale to tylko ograniczenie mojego złego przykładu. Zmienna zostanie pierwotnie zadeklarowana jako instancja interfejsu.

+7

To brzmi jak zły projekt. Powinieneś używać polimorfizmu, zamiast znać swoją metodę o konkretnych rodzajach betonu. Co stanie się, jeśli dodasz później? –

+4

Czy to nie jest celem interfejsu? Nie powinieneś przejmować się tym, jaki konkretny typ ma tak długo, jak implementuje interfejs. –

+2

+1 do Johna i Chrisa, nie tylko jest to zły projekt, ale pytanie nie ma sensu. –

Odpowiedz

56
Type objectType = myObject.GetType(); 

Jeżeli nadal daje konkretny typ, w zależności np.

+2

Tak, wywołanie "myObject.GetType()" will NIGDY nie zwraca typu interfejsu. – TcKs

+0

Parametr 'PerfomAction' to' object', ale nie mógł tego zrobić: 'IA.getType()' dla np. –

2

Nie można mieć instancji interfejsu. Zatem określenie, czy masz do czynienia z interfejsem, czy konkretnym typem, nie jest możliwe, ponieważ zawsze będziesz miał do czynienia z konkretnym typem. Więc nie jestem pewien, czy twoje pytanie ma sens. Co dokładnie próbujesz zrobić i dlaczego?

+2

+1 dokładnie, w rzeczywistości jego przykład działa dobrze. –

5

Co robisz jest naprawdę łóżek projekt, ale nie trzeba użyć refleksji można sprawdzić jak to

void PerformAction(object myObject) 
{ 
    B objectType = myObject as B; // Here is where I get typeof(IA) 
    if (objectType != null) 
    { 
     //use objectType.b 
    } 
    else 
    { 
     //Same with A 
    } 
    // snip - other actions on objectType 
} 
+2

To wciąż dość kiepski projekt, ponieważ nadal jesteś zależny od rodzaju betonu. To w dużej mierze pokonuje cel posiadania interfejsu w pierwszej kolejności ... – jrista

+0

Krzyczę w mojej głowie: "LSP, ISP, DIP !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!! " – Sebastien

0

Może szukasz is operator

void PerformAction(object myObject) 
{ 
    if (myObject is B) 
    { 
     B myBObject = myObject as B; 
     myBObject.b = 1; 
    } 

    if (myObject is C) 
    { 
     C myCObject = myObject as C; 
     myCObject.c = 1; 
    } 

    // snip - other actions on objectType 
} 
+0

przesyłasz go dwukrotnie. Użyj od razu operatora 'as' i sprawdź null później – nawfal

4

Muszę zgodzić się o złej konstrukcji. Jeśli masz interfejs, powinno to być spowodowane tym, że musisz wykorzystać jakąś wspólną funkcjonalność bez dbania o to, jaka jest konkretna implementacja. Biorąc pod uwagę Twój przykład, wygląda na to, że metoda PerformAction powinna być częścią interfejsu:

public interface IA 
{ 
    int a { get; set; } 
    void PerformAction(); 
} 

public class B: IA 
{ 
    public int a { get; set; } 
    public int b { get; set; } 

    public void PerformAction() 
    { 
     // perform action specific to B 
    } 
} 

public class C : IA 
{ 
    public int a { get; set; } 
    public int c { get; set; } 

    public void PerformAction() 
    { 
     // perform action specific to C 
    } 
} 

void PerformActionOn(IA instance) 
{ 
    if (instance == null) throw new ArgumentNullException("instance"); 

    instance.PerformAction(); 

    // Do some other common work... 
} 


B b = new B(); 
C c = new C(); 

PerformActionOn(b); 
PerformActionOn(c); 
Powiązane problemy