代码之家  ›  专栏  ›  技术社区  ›  D G

即使返回类型为IEnumerable,也无法屈服<U>

  •  0
  • D G  · 技术社区  · 2 年前

    考虑以下琐碎的示例:

    class Filter<T, U>
        where T : IEnumerable<U>
        where U : IEquatable<U>
    {
        private readonly U id;
    
        public Filter(U id) => this.id = id;
    
        public T Eval_A(T items)
        {
            foreach (var item in items)
                if (item.Equals(id))
                    yield return item;
        }
    
        public IEnumerable<U> Eval_B(IEnumerable<U> items)
        {
            foreach (var item in items)
                if (item.Equals(id))
                    yield return item;
        }
    }
    

    尽管 T 是类型 IEnumerable<U> ,仍然发生错误 T Eval_A(T items) 如下所示。

    “accessor”的主体不能是迭代器块,因为“type”不是迭代器接口类型

    MSDN表示:

    如果使用迭代器访问器,但返回类型不是迭代器接口类型之一,则会发生此错误: IEnumerable , IEnumerable<T> , IEnumerator , IEnumerator<T> 。若要避免此错误,请使用迭代器接口类型之一作为返回类型。

    我认为返回类型确实符合要求。

    我在这里错过了什么?

    0 回复  |  直到 2 年前
        1
  •  2
  •   Sweeper    2 年前

    方法的返回类型必须是 确切地 其中之一 IEnumerable , IEnumerable<T> , IEnumerator IEnumerator<T> ,而不是 T ,是实现的某种类型 IEnumerable<U>

    这是因为迭代器方法的工作方式是,编译器生成一个实现上述接口之一的类型 MoveNext Current 正确实现,使其与方法的行为匹配,然后重写方法以返回该类型的实例。

    例如,对于:

    public IEnumerable<int> GetSingleDigitNumbersLoop()
    {
        int index = 0;
        while (index < 10)
            yield return index++;
    }
    

    生成以下内容(使用 SharpLab.io ):

    [IteratorStateMachine(typeof(<GetSingleDigitNumbersLoop>d__0))]
    public IEnumerable<int> GetSingleDigitNumbersLoop()
    {
        return new <GetSingleDigitNumbersLoop>d__0(-2);
    }
    
    [CompilerGenerated]
    private sealed class <GetSingleDigitNumbersLoop>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable, IEnumerator
    {
        private int <>1__state;
    
        private int <>2__current;
    
        private int <>l__initialThreadId;
    
        private int <index>5__2;
    
        int IEnumerator<int>.Current
        {
            [DebuggerHidden]
            get
            {
                return <>2__current;
            }
        }
    
        object IEnumerator.Current
        {
            [DebuggerHidden]
            get
            {
                return <>2__current;
            }
        }
    
        [DebuggerHidden]
        public <GetSingleDigitNumbersLoop>d__0(int <>1__state)
        {
            this.<>1__state = <>1__state;
            <>l__initialThreadId = Environment.CurrentManagedThreadId;
        }
    
        [DebuggerHidden]
        void IDisposable.Dispose()
        {
        }
    
        private bool MoveNext()
        {
            int num = <>1__state;
            if (num != 0)
            {
                if (num != 1)
                {
                    return false;
                }
                <>1__state = -1;
            }
            else
            {
                <>1__state = -1;
                <index>5__2 = 0;
            }
            if (<index>5__2 < 10)
            {
                <>2__current = <index>5__2++;
                <>1__state = 1;
                return true;
            }
            return false;
        }
    
        bool IEnumerator.MoveNext()
        {
            //ILSpy generated this explicit interface implementation from .override directive in MoveNext
            return this.MoveNext();
        }
    
        [DebuggerHidden]
        void IEnumerator.Reset()
        {
            throw new NotSupportedException();
        }
    
        [DebuggerHidden]
        IEnumerator<int> IEnumerable<int>.GetEnumerator()
        {
            if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
            {
                <>1__state = 0;
                return this;
            }
            return new <GetSingleDigitNumbersLoop>d__0(0);
        }
    
        [DebuggerHidden]
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<int>)this).GetEnumerator();
        }
    }
    

    <GetSingleDigitNumbersLoop>d__0 是实现的类型 IEnumerable<int> 那个 GetSingleDigitNumbersLoop 被重写为返回。

    现在,如果 GetSingleDigitNumbersLoop 被声明为返回其他类型,如类型参数 T 例如,以下操作不起作用:

    public T GetSingleDigitNumbersLoop()
    {
        return new <GetSingleDigitNumbersLoop>d__0(-2);
    }
    

    因为 <GetSingleDigitNumbersLoop>d_0 不一定是 T 。事实上,它几乎永远不会,因为它是编译器生成的类型!

    另请参阅: yield statement implementation