2013-07-15 20 views
5
  1. mam ogólne klasy A nie < T>, który implementuje IEnumerable < T []>.
  2. chcę mieć wygodę otoki B, która dziedziczy A < char> i wdraża IEnumerable < ciąg>.IEnumerable paradox

    public class A<T> : IEnumerable<T[]> 
    { 
        public IEnumerator<T[]> GetEnumerator() 
        { 
         return Enumerate().GetEnumerator(); 
        } 
    
        IEnumerator IEnumerable.GetEnumerator() 
        { 
         return GetEnumerator(); 
        } 
    
        protected IEnumerable<T[]> Enumerate() 
        { 
         throw new System.NotImplementedException(); 
        } 
    } 
    
    public class B : A<char>, IEnumerable<string> 
    { 
        public IEnumerator<string> GetEnumerator() 
        { 
         return Enumerate().Select(s => new string(s)).GetEnumerator(); 
        } 
    
        IEnumerator IEnumerable.GetEnumerator() 
        { 
         return GetEnumerator(); 
        } 
    } 
    

Teraz to działa perfekcyjnie, foreach typ zmiennej jest wywnioskować być ciąg:

B b = new B(); 
foreach (var s in b) 
{ 
    string[] split = s.Split(' '); 
} 

Ale nie będzie to skompilować, mówiąc: „Argumenty typu nie można wywnioskować z użytkowania , spróbuj podać argumenty typu jawnie ":

string[] strings = b.ToArray(); 

jednak to działa:

string[] strings = b.ToArray<string>(); 

Czy ktoś może wyjaśnić zachowanie kompilatora?

Oczywiście, B realizuje oba IEnumerable < char []> i IEnumerable < ciąg> i prawdopodobnie nie może dowiedzieć się, który z nich chcę zadzwonić, ale dlaczego to działa dobrze w „foreach” próbki ?

Proszę, nie sugeruj mi, żebym rozwiązał mój problem przez kompozycję - to dla mnie ostatnia deska ratunku.

Odpowiedz

2

Różnica jest następująca:

foreach rzeczywiście wygląda na publiczną metodę o nazwie GetEnumerator. To naprawdę nie obchodzi IEnumerable<T>. Twoja klasa B ma tylko jedną publiczną metodę o nazwie GetEnumerator: zdefiniowaną w , która ukrywa się pod numerem .

ToArray z drugiej strony jest metodą rozszerzenia na IEnumerable<T>. Ponieważ twoja klasa jest zarówno IEnumerable<string>, jak i IEnumerable<char[]>, wywołanie jest niejednoznaczne między dwoma głównymi argumentami: string i char[].

2
Pętla

foreach nie korzysta z implementacji IEnumerable lub IEnumerable<T>. Możesz użyć foreach, nawet jeśli twoja klasa nie implementuje żadnego z nich. Potrzebna jest tylko metoda GetEnumerator, która zwraca implementację IEnumerator.

Sprawdź to pytanie: How is foreach implemented in C#?

Dlatego klasa współpracuje z foreach i nie robi z ToArray().