为什么defaultifempty以这种方式实现?[英] Why is DefaultIfEmpty implemented this way?

本文是小编为大家收集整理的关于为什么defaultifempty以这种方式实现?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

追求System.Linq.Enumerable.DefaultIfEmpty的实现使我使用了这种方法.除了以下古朴的细节外,它看起来还不错:

// System.Linq.Enumerable
[IteratorStateMachine(typeof(Enumerable.<DefaultIfEmptyIterator>d__90<>))]
private static IEnumerable<TSource> DefaultIfEmptyIterator<TSource>(IEnumerable<TSource> source, TSource defaultValue)
{
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext())
        {
            do
            {
                yield return enumerator.Current;
            }
            while (enumerator.MoveNext());
        }
        else
        {
            yield return defaultValue;
        }
    }
    IEnumerator<TSource> enumerator = null;
    yield break;
    yield break;
}

1)为什么一旦确定序列不是空的,为什么代码必须在整个序列上迭代?

2)为什么末端的产量在最后两次?

3)当没有其他参考时,为什么在结尾处明确将enumerator设置为null?

我会留下它:

// System.Linq.Enumerable
[IteratorStateMachine(typeof(Enumerable.<DefaultIfEmptyIterator>d__90<>))]
private static IEnumerable<TSource> DefaultIfEmptyIterator<TSource>(IEnumerable<TSource> source, TSource defaultValue)
{
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext())
        {
            do
            {
                yield return enumerator.Current;
            }
            // while (enumerator.MoveNext());
        }
        else
        {
            yield return defaultValue;
        }
    }
    // IEnumerator<TSource> enumerator = null;
    yield break;
    // yield break;
}

推荐答案

DefaultIfEmpty需要采取以下操作:

  1. 如果源枚举没有条目,则需要充当具有单个值的枚举;默认值.

  2. 如果源头枚举不是空的,则需要充当源头.因此,它需要产生所有值.

其他推荐答案

因为当您开始枚举时,此代码被用作另一个枚举级别,您必须枚举整个内容.

如果您只是yield return第一个并停止使用此枚举者的代码,将认为只有一个值.因此,您必须枚举所有内容,并且yield return向前列出.

您当然可以做return enumerator,这将起作用,但是在调用MoveNext()之后,这将导致第一个值跳过.如果还有另一种检查值是否存在的方法,那么这将是这样做的方法.

其他推荐答案

确定序列不是空的,为什么代码必须在整个序列上迭代?

您可以阅读 msdn 关于DefaultIfEmtpy返回值:

an IEnumerable<T>对象,该对象包含TSource类型的默认值,如果源为空;否则,来源.

因此,如果枚举是空的,则结果是包含默认值的枚举,但是如果枚举不为空,则返回相同的枚举(不仅是第一个元素).

看来,这种方法仅是关于仅检查枚举是否包含元素,但事实并非如此.

为什么最后两次打破屈服?

没有想法:)

本文地址:https://www.itbaoku.cn/post/1556742.html

问题描述

Chasing the implementation of System.Linq.Enumerable.DefaultIfEmpty took me to this method. It looks alright except for the following quaint details:

// System.Linq.Enumerable
[IteratorStateMachine(typeof(Enumerable.<DefaultIfEmptyIterator>d__90<>))]
private static IEnumerable<TSource> DefaultIfEmptyIterator<TSource>(IEnumerable<TSource> source, TSource defaultValue)
{
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext())
        {
            do
            {
                yield return enumerator.Current;
            }
            while (enumerator.MoveNext());
        }
        else
        {
            yield return defaultValue;
        }
    }
    IEnumerator<TSource> enumerator = null;
    yield break;
    yield break;
}

1) Why does the code have to iterate over the whole sequence once it has been established that the sequence is not empty?

2) Why the yield break two times at the end?

3) Why explicitly set the enumerator to null at the end when there is no other reference to it?

I would have left it at this:

// System.Linq.Enumerable
[IteratorStateMachine(typeof(Enumerable.<DefaultIfEmptyIterator>d__90<>))]
private static IEnumerable<TSource> DefaultIfEmptyIterator<TSource>(IEnumerable<TSource> source, TSource defaultValue)
{
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext())
        {
            do
            {
                yield return enumerator.Current;
            }
            // while (enumerator.MoveNext());
        }
        else
        {
            yield return defaultValue;
        }
    }
    // IEnumerator<TSource> enumerator = null;
    yield break;
    // yield break;
}

推荐答案

DefaultIfEmpty needs to act as the following:

  1. If the source enumerable has no entries, it needs to act as an enumerable with a single value; the default value.

  2. If the source enumerable is not empty, it needs to act as the source enumerable. Therefore, it needs to yield all values.

其他推荐答案

Because when you start enumerating and this code is used as another level of enumeration you have to enumerate the whole thing.

If you just yield return the first one and stop there the code using this enumerator will think there is only one value. So you have to enumerate everything there is and yield return it forward.

You could of course do return enumerator and that would work, but not after the MoveNext() has been called since that would cause the first value to be skipped. If there was another way to check if values exist then this would be the way to do it.

其他推荐答案

Why does the code have to iterate over the whole sequence once it has been established that the sequence is not empty?

As you can read in MSDN about DefaultIfEmtpy return value:

An IEnumerable<T> object that contains the default value for the TSource type if source is empty; otherwise, source.

So, if the enumerable is empty the result is a enumerable containing the default value, but if the enumerable isn't empty the same enumerable is returned (not only the first element).

It may seem that this method is about checking only whether an enumerable contains elements or not, but it is not the case.

Why the yield break two times at the end?

No ideas :)