2011-01-31 11 views
6

Powiel możliwe:
Why can't I use interface with explicit operator?Dlaczego C# nie zezwala typom wykorzystującym kompozycję na niejawne konwersje dla interfejsów?

Kiedy to zrobić:

public struct Effect 
{ 
    public IEffect IEffect { get; private set; } 

    public Effect (IEffect effect) 
    { 
     this.IEffect = effect; 
    } 

    public static implicit operator IEffect (Effect effect) 
    { 
     return effect.IEffect; 
    } 

    public static explicit operator Effect (IEffect effect) 
    { 
     return new Effect (effect); 
    } 
} 

otrzymuję błąd kompilatora takiego:

„ImageEditor.Effect .chochlik legalny operator ImageEditor.IEffect (ImageEditor.Effect) ": Konwersje zdefiniowane przez użytkownika do lub z interfejsu są niedozwolone.

Dlaczego nie są one dozwolone? Czy to nie jest dobra praktyka?

+0

Możliwe duplikaty: http://stackoverflow.com/questions/2433204/why-cant-i-use-interface-with-expic-operator-operator –

Odpowiedz

7

Jest to szczegółowo opisane w sekcji 10.10.3 specyfikacji języka C#.

Podsumowanie powód, dlaczego mimo to ...

  • operatory konwersji nie powinien zastępować wbudowanej konwersji. Umożliwienie to właśnie prowadzi do wyjątkowo zagmatwanej zachowania
  • W ogóle to nie jest możliwe, aby ustalić, czy niejawna konwersja do interfejsu zastępuje wbudowaną konwersją, a więc jest to zabronione
+0

Dzięki Jared, w twoim drugim powodem, przez "nie możliwe" masz na myśli przez kompilator lub użytkownika do ustalenia? Zakładam, że to użytkownik. –

+0

Głównym powodem jest to, że jeśli obiekt można przekonwertować na IOneInterface i ITwoInterface, wówczas odniesienie obiektu za pośrednictwem IOneInterface powinno być możliwe do odlewania do ITwointerfejsu. Zastępujący operatorzy mogą to złamać. (przynajmniej to było moje zrozumienie) –

+1

@Joan not possible odnosi się do zdolności kompilatora do określenia tego. Uwaga: jest to ograniczone do ogólnego przypadku, ponieważ istnieją określone przypadki (klasy "struct" i "sealed"), w których kompilator może dokonać tego określenia. Ale zespół C# zdecydował się na to (co do tego, dlaczego mogę tylko spekulować, ale domyślam się, że jest spójny). – JaredPar

1

Głównym powodem jest to, że obiekt, który implementuje interfejs jest zawsze niejawnie wymienialny na jego klasę podstawową i zawsze jest jawnie wymienialny ze swojej klasy bazowej na samą siebie. Usunięcie tego zachowania jest zbyteczne i mylące, i nie można zastąpić wszystkich niezbędnych zachowań, aby działało poprawnie, a więc jest zabronione. W twoim przypadku nadpisujesz niektóre, ale nie wszystkie zachowania związane z dziedziczeniem. Na przykład najlepszych praktyk podczas odlewania jest wyraźnie:

IEffect anIEffectInstance = GetEffectAsInterface(); 

if(anIEffectInstance is Effect) //<--you cannot override this behavior to return true, 
    var interfaceAscConcrete = (Effect)anIEffectInstance; //<-- so this overridden code would never execute 
0

Brzmi jak pytanie Jon Skeet lub tym podobne, ale wezmę szansę na to tak.

Niejawny operator, który opisałeś, byłby w dużej mierze niepotrzebny. Jeśli Effect implementuje już IEffect, możesz użyć obiektu Effect w dowolnym miejscu, w którym potrzebny jest obiekt implementujący IEffect bez konieczności przejmowania się konwersją zdefiniowaną przez użytkownika.

Wyraźna kwestia operatora może być nieco bardziej filozoficzna. Rozumiem, że celem niejawnych i jawnych konwersji jest przekonwertowanie obiektu jednego typu na obiekt innego typu, którego relacja nie jest już z jakiegoś powodu oczywista dla kompilatora. Interfejs nie jest jednak obiektem. Nie można bezpośrednio utworzyć interfejsu; raczej interfejs musi być implementowany przez jakąś klasę. Podczas korzystania z niejawnych lub jawnych konwersji wynikowy obiekt nie jest skojarzony z typem z poprzednim obiektem. Oznacza to, że obiekt powstały w wyniku konwersji musi być w stanie stać niezależnie i mieć rzeczywisty typ obiektu, którego interfejs sam z siebie nie obsługuje.

Być może bardziej bezpośrednio: Jaki byłby konkretny typ wyniku niejawnej konwersji? Kompilator nie ma możliwości poznania, więc nie może utworzyć instancji obiektu.

Jeśli naprawdę potrzebujesz czegoś takiego, chciałbyś stworzyć abstrakcyjną klasę bazową, która implementuje interfejs. Powinieneś wtedy móc "przekonwertować" na i z abstrakcyjnej klasy bazowej, która ma typ obiektu.

+0

Dzięki, ale Effect nie implementuje IEffect. –

+0

@Joan Venge Nie ma za co, ale czy nie należy implementować efektów IEffect? Czy to, co usiłujesz osiągnąć, będzie obsługiwane przez wzór państwowy? (http://en.wikipedia.org/wiki/State_pattern) W skrócie, zaimplementowałbyś IEffect z Effect i używał metod i właściwości przechowywanego IEffect do implementacji IEffect w klasie Effect. – Andrew

+0

Dzięki, nigdy nie słyszałem wzorca stanu, ale ten IEffect jest opakowaniem do niezarządzanego API. Używam więc kompozycji, a nie dziedziczenia, ponieważ ma wiele elementów, których nie chcę implementować i wystawiać użytkownikom mojego API. –

Powiązane problemy