2011-07-19 24 views
14
public abstract class EntityBase { ... } 

public interface IFoobar 
{ 
    void Foo<T>(int x) 
     where T : EntityBase, new(); 
} 

public interface IFoobar<T> 
    where T : EntityBase, new() 
{ 
    void Foo(int x); 
} 

public class Foobar<T> : IFoobar, IFoobar<T> 
    where T : EntityBase, new() 
{ 
    public void Foo(int x) { ... } 

    void IFoobar.Foo<T>(int x) { Foo(x); } 
} 

dostaję ostrzeżenie kompilatora: Type parameter 'T' has the same name as the type parameter from outer type '...'Typ parametru „T” ma taką samą nazwę jak parametr typu od rodzaju zewnętrznego „...”

próbowałem robić: void IFoobar.Foo<U>(int x) { Foo(x); }, jednak wtedy nie mogę gwarantują, że U i T są takie same. Sposób, w jaki realizowana jest klasa Foobar, jest bardzo ważny, aby były takie same.

Próbowałem również: void IFoobar.Foo<U>(int x) where U : T { Foo(x); }, ale to nie gwarantuje, że U i T są równe i nie pozwala mi to przedefiniować ograniczenia, ponieważ został zdefiniowany na interfejsie.

+0

Co próbujesz zrobić? Dlaczego ponownie definiujesz T, jeśli jest on określony w klasie? Jeśli masz potrzebę zdefiniowania go, to powinno być oddzielne, w przeciwnym razie klasa T jest już określona przez klasę. Jeśli chcesz rozwiązać ten problem, umieść T na interfejsie, jeśli możesz. Właśnie to zrobiłem, gdy znajdę się w duplikacie specyfikacji typu. –

Odpowiedz

8

można zrobić jedną z dwóch rzeczy:

  1. zignorować ostrzeżenie i uczynić obu typów T.
  2. Wykonaj test run-time i wyjątek:

    if (typeof(T) != typeof(U)) throw Exception("Not the same type"); 
    

Jak inni stwierdzili, być może trzeba przemyśleć jaki jesteś projektowanie interfejsów.

3

Spróbuj

void IFoobar.Foo<U>(int x) { Foo(x); } 

oczywiście, że nadal nie gwarantuje, że U jest taka sama jak T. Ty nie można wymusić, aby wymusić to podczas kompilacji, ponieważ podczas implementowania interfejsu musisz musi przestrzegać jego zasad - i IFoobar nie nakłada takiego ograniczenia na Foo<T>, a jeśli to zrobisz, nie będzie już implementować interfejsu (z definicji, ponieważ jesteś bardziej rygorystyczny, a mimo to twierdzisz, że nie jesteś).

Możesz spróbować sprawdzić to w czasie wykonywania, ale to trochę "oszustwo" (ponieważ tak naprawdę nie dostosowujesz się do interfejsu).

+0

Podczas gdy zachowuje ograniczenie dla typu, nie gwarantuje, że 'T' i' U' są takie same. –

+0

To nie gwarantuje, że U jest równe T, i nie mogę ponownie zdefiniować ograniczeń na U, ponieważ zostały one zdefiniowane w interfejsie. – michael

+0

To nie zostanie skompilowane. Ograniczenia dotyczące nadpisywania i jawnych metod implementacji interfejsu są dziedziczone z metody bazowej, więc nie można ich bezpośrednio określić. Usuń klauzulę where, aby to naprawić. –

12

Największym problemem jest to, że twoje interfejsy nie są dobrze zdefiniowane i nie pasują do intencji twojego kodu.

Jeśli Twój T nie jest widoczny publicznie na interfejsie, to zewnętrzny kod nie musi nawet wiedzieć, że istnieje T. Musisz albo utworzyć metody, które otrzymają lub zwrócą T, albo mają jakąś właściwość typu T, albo powinieneś całkowicie pozbyć się T i uczynić swoje interfejsy nietypowymi.

Gdy już to zrobisz, stanie się bardziej oczywiste, dlaczego nie potrzebujesz tutaj dwóch różnych interfejsów i nie powinieneś już ich łączyć.

Jeśli okaże się, że zrobić potrzebują wersji, która pobiera T oraz wersję non-T, to bardziej idiomatycznych sposób, aby to zrobić jest przechodzą wokół object zamiast T:

public interface IFoo 
{ 
    void DoSomething(object o); 
    object DoSomethingElse(); 
} 

public interface IFoo<T> 
{ 
    void DoSomething(T item); 
    T DoSomethingElse(); 
} 

Zobacz przykłady takich interfejsów, jak IEnumerable, ICollection, IList itp.

Ale rozważ ostrożnie. Ten ostatni kompromis projektowy (posiadający zarówno wersję ogólną, jak i obiektową) zawsze pozostawia wiele do życzenia.

Będziesz poświęcić jeden z nich:

  • projektowania dobry interfejs, który komunikuje się bezpośrednio umowę projektowe (Jeśli rzucać wyjątki czy nie-op, gdy niewłaściwy typ jest przekazywana)
  • Type bezpieczeństwa i zmniejszenie błędów, które idzie z nim (jeśli poprawnie działać na dowolnym-starego obiektu)