加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 向IEnumerator投射IEnumerable做什么

发布时间:2020-12-15 23:38:01 所属栏目:百科 来源:网络整理
导读:我正在培训初学者一些C#的核心概念.在为随机数创建IEnumerable时,他的代码中的错误建议投射IEnumerable T.到IEnumerator T 我知道这些接口都没有相互实现,所以令我印象深刻的是ReSharper,编译器和运行时都没有引发异常. 这是一些示例代码: public class Som
我正在培训初学者一些C#的核心概念.在为随机数创建IEnumerable时,他的代码中的错误建议投射IEnumerable< T>.到IEnumerator< T>

我知道这些接口都没有相互实现,所以令我印象深刻的是ReSharper,编译器和运行时都没有引发异常.

这是一些示例代码:

public class SomeEnumerable : IEnumerable<int>
{
    private readonly IEnumerable<int> _numbers;

    public SomeEnumerable()
    {
        _numbers = Enumerable.Range(0,10);
    }

    public IEnumerator<int> GetEnumerator()
    {
        return (IEnumerator<int>) _numbers;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

出乎意料的是,GetEnumerator-Method编译得非常好.当初学者错误地将私人字段“_numbers”放入时,ReSharper甚至建议添加我已包含的显式演员.

现在考虑以下测试代码:

var someEnumerable = new SomeEnumerable();
Console.WriteLine($"Number of elements: {someEnumerable.Count()}");

Count() – Method调用枚举器,输出如下:

Number of elements: 0

奇怪的是,如果你改变类的构造函数,使它使用IList< T>对于私人领域

public SomeEnumerable()
{
    _numbers = Enumerable.Range(0,10).ToArray();
}

代码抛出正确的InvalidCastException.

我知道Enumerable.Range()在其实现中使用yield语句,并且只要实现了GetEnumerator方法,编译器就可以做一些魔术,所以也许这是一个提示.

因此,我的问题是:

>为什么演员合法,为什么没有警告? (编译时间/ Resharper)
>为什么你可以在没有得到警告的情况下将IEnumerable转换为IEnumerator而不是IList到IEnumerator(ReSharper)
>为什么通过Count / foreach / etc调用GetEnumerator.产生空结果?
>如果有充分理由这样做,框架的哪一部分可以利用它?

一些澄清:
我知道不应该这样做,我知道它永远不会以这种方式工作.但我感兴趣的是为什么代码导致IL编译和执行完全正常但产生如此奇怪的结果

解决方法

Why is the cast legal and why isn’t there a warning?

演员的全部意义在于你告诉编译器,“我知道你不认为这种类型实际上是另一种类型,但我比你知道更多,让我把它看作是这个其他类型如果我错了,在运行时抛出异常.

Why can you cast an IEnumerable to an IEnumerator but not an IList to an IEnumerator without getting a warning (ReSharper)

你不能投出任何IEnumerable< T>到IEnumerator< T>.这个特定对象恰好实现了两个接口.其他对象,例如你编写的SomeEnumerable,只会实现其中一个,而像这样的强制转换对它们来说会失败(在运行时).

Why does invoking GetEnumerator by Count/foreach/etc. yield an empty result?

该对象不期望您将其转换为另一种类型并开始在其上调用方法.你违反了合同类型.如果你想让它正常工作,请调用GetEnumerator,它会为你提供一个合适的枚举器.实际上,由于您破坏了初始化其数据的方法,因此您将获得一个未正确初始化的枚举器.

If there is a good reason for this to work,which part of the framework makes use of that?

它只是一个看起来像这样的类型:

public class SomeClass: IEnumerable<int>,IEnumerator<int>
{ 
    //...
}

如果你愿意,你可以写一个这样的类.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读