2009-04-21 7 views
21

Czy można zdefiniować funkcję, która przyjmuje parametr, który musi implementować dwa interfejsy?Czy jest możliwe, aby parametr implementował dwa interfejsy?

(Oba interfejsy są te po prostu pamiętał poza czubek mojej głowy; nie te Chcę używać)

private void DoSomthing(IComparable, ICollection input) 
{ 

} 
+0

Można użyć [tej samej sztuczki, co w przypadku deklarowania zmiennej składowej] (http://stackoverflow.com/a/4940249/429091), chociaż to podejście wymaga implementacji klas w celu włączenia wzorca. – binki

Odpowiedz

49

Można:

1) określić interfejs, który dziedziczy zarówno wymaganych interfejsów:

public interface ICombinedInterface : IComparable, ICollection {... } 

private void DoSomething(ICombinedInterface input) {... } 

2) stosowanie leków generycznych:

private void DoSomething<T>(T input) 
    where T : IComparable, ICollection 
{...} 
+3

w VB.Net: Private Sub DoSomthing (Of ​​T As {IComparable, ICollection }) (ByVal input As T) ...Koniec Sub – Pondidum

+0

Czy istnieje zysk za pomocą jednego z tych rozwiązań, ponieważ mają dwa oddzielne parametry? Intuicyjnie wydaje się, że byłoby to przydatne, ale staram się wymyślić konkretny przykład. – CurtainDog

+0

Nie mogę w tej chwili myśleć o jednym, ale chciałem to zrobić kilka dni temu. i mając jeden parametr wygląda lepiej niż wywołanie DoSomthing (testData, testData) i tym samym dwukrotne przekazanie tego samego wystąpienia. – Pondidum

5

Można odziedziczyć inny interfejs z tych dwóch interfejsów i zrobić parametr wdrożyć że berło.

+1

działa tylko wtedy, gdy można zmienić WSZYSTKIE klasy, które implementują oba interfejsy, aby zaimplementować nowy interfejs. –

+0

Cóż, nie wszystkie z nich koniecznie. Tylko te, których potrzebujesz jako parametr dla tej metody. –

2

No tak, i nie.

Możesz, jak Steve zasugerował, stworzyć kolejny, trzeci interfejs, który opada z dwóch, które chcesz, i użyć go dla typu parametru.

Jednak będzie to również wymagać, aby używana klasa implementowała również trzeci interfejs.

Innymi słowy, to nie będzie działać:

public interface I1 { } 
public interface I2 { } 
public class C : I1, I2 { } 

public interface I3 : I1, I2 { } 
public class YourClass 
{ 
    public void Test(I3 i) { } 
} 

... 
YourClass yc = new YourClass(); 
C c = new C(); 
yc.Test(c); // won't work, C does not implement I3 

można jednak oszukać kompilator do tego, co chcesz w drodze generycznych.

public class YourClass 
{ 
    public void Test<T>(T i) where T: I1, I2 { } 
} 

Teraz będzie działać. Nadal nie jestem w 100% pewny, że nie dam ci jeszcze innych problemów, musiałbym o tym pomyśleć.

1

Podejście funkcji ogólnej, o którym mowa powyżej, jest dobre, z jednym dużym zastrzeżeniem: aby typograficznie obiekt mógł zostać przekazany do rutyny z wieloma ogólnymi ograniczeniami, trzeba znać typ, który spełnia te ograniczenia i jest rodzicielskim typem rzutowanego obiektu. Procedura, która akceptuje taki obiekt, będzie znała taki typ (został przekazany jako ogólny parametr typu), ale nie ma dobrego sposobu, aby klasa utrzymywała takie informacje i używała ich później. Jeśli wiele niezwiązanych typów implementuje zarówno IFoo, jak i IBar, trudno byłoby zaprojektować procedurę, która mogłaby zaakceptować wiele niepowiązanych instancji obiektu, zapisać je na liście lub czymś, a następnie przekazać wszystkie pozycje na liście do procedury z ogólnym parametrem IFoo + IBar.

Jeśli taki scenariusz może być niezbędny, najlepszym podejściem byłoby posiadanie nietypowego odpowiednika dla każdej ogólnej procedury, która mogłaby zaakceptować np. parametr typu IFoo i w razie potrzeby odrzuć go do IBar. Można następnie przechowywać wszystkie pozycje na liście i przekazywać je do procedury. Można by stracić bezpieczeństwo typowe metody, ale czasami doskonałe bezpieczeństwo typu nie jest osiągalne.

Powiązane problemy