Multiple IEnumerable implementations paradox

岁酱吖の 提交于 2019-12-19 19:52:11

问题


  1. I have a generic class A<T>, that implements IEnumerable<T[]>.
  2. I want to have a convenience wrapper B that inherits from A<char> and implements IEnumerable<string>.

    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();
        }
    }
    

Now, this works perfectly fine, foreach variable type is inferred to be string:

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

But this won't compile, saying "The type arguments cannot be inferred from usage, try specifying the type arguments explicitly":

string[] strings = b.ToArray();

However, this works:

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

Can anyone explain this compiler behavior?

Obviously, B implements both IEnumerable<char[]> and IEnumerable<string> and probably it can't figure out which of them I want to call, but why it works fine in "foreach" sample?

Please, don't suggest me to solve my problem by composition - this is the last resort for me.


回答1:


The difference is the following:

foreach actually looks for a public method called GetEnumerator. It doesn't really care for IEnumerable<T>. Your class B only has one public method named GetEnumerator: The one defined in B which hides the one defined in A.

ToArray on the other hand is an extension method on IEnumerable<T>. As your class is both IEnumerable<string> and IEnumerable<char[]> the call is ambiguous between the two generic arguments string and char[].




回答2:


foreach loop does not use IEnumerable or IEnumerable<T> implementation. You can use foreach even if your class doesn't implement any of them. The only thing it needs is GetEnumerator method that returns IEnumerator implementation.

Check this question: How is foreach implemented in C#?

That's why your class works with foreach and doesn't with ToArray().



来源:https://stackoverflow.com/questions/17652974/multiple-ienumerable-implementations-paradox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!