Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么Enumerable.Empty()返回空数组?_C#_Linq_Linq To Objects - Fatal编程技术网

C# 为什么Enumerable.Empty()返回空数组?

C# 为什么Enumerable.Empty()返回空数组?,c#,linq,linq-to-objects,C#,Linq,Linq To Objects,我希望Enumerable.Empty()的实现如下: public static IEnumerable<TResult> Empty<TResult>() { yield break; } 公共静态IEnumerable Empty() { 屈服断裂; } 但是实现是这样的: public static IEnumerable<TResult> Empty<TResult>() { return EmptyEnumerabl

我希望Enumerable.Empty()的实现如下:

public static IEnumerable<TResult> Empty<TResult>()
{
    yield break;
}
公共静态IEnumerable Empty()
{
屈服断裂;
}
但是实现是这样的:

public static IEnumerable<TResult> Empty<TResult>()
{
    return EmptyEnumerable<TResult>.Instance;
}

internal class EmptyEnumerable<TElement>
{
    private static volatile TElement[] instance;

    public static IEnumerable<TElement> Instance
    {
        get
        {
            if (EmptyEnumerable<TElement>.instance == null)
                EmptyEnumerable<TElement>.instance = new TElement[0];
            return (IEnumerable<TElement>)EmptyEnumerable<TElement>.instance;
        }
    }
}
公共静态IEnumerable Empty()
{
返回EmptyEnumerable.Instance;
}
内部类EmptyEnumerable
{
私有静态易失性远程通信[]实例;
公共静态IEnumerable实例
{
得到
{
if(EmptyEnumerable.instance==null)
EmptyEnumerable.instance=新远程通讯[0];
return(IEnumerable)EmptyEnumerable.instance;
}
}
}
为什么实现比一行代码更复杂?返回缓存的数组而不(产生)返回任何元素是否有优势


注意:我永远不会依赖方法的实现细节,但我只是好奇。

这样做是有意义的,因为在这种情况下,您将为相同类型的所有空实例创建一个数组,这将需要更少的内存。这就是为什么单个阵列实例是静态的

由于不能更改没有元素的数组,因此它不会被任何代码弄脏。

编译(使用启用优化的LINQpad)

对于
MyEmpty
方法,它是:

MyEmpty:
IL_0000:  ldc.i4.s    FE 
IL_0002:  newobj      15 00 00 0A 
IL_0007:  stloc.0     
IL_0008:  ldloc.0     
IL_0009:  ret         

<MyEmpty>d__0`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator:
IL_0000:  call        System.Environment.get_CurrentManagedThreadId
IL_0005:  ldarg.0     
IL_0006:  ldfld       0E 00 00 0A 
IL_000B:  bne.un.s    IL_0022
IL_000D:  ldarg.0     
IL_000E:  ldfld       0F 00 00 0A 
IL_0013:  ldc.i4.s    FE 
IL_0015:  bne.un.s    IL_0022
IL_0017:  ldarg.0     
IL_0018:  ldc.i4.0    
IL_0019:  stfld       0F 00 00 0A 
IL_001E:  ldarg.0     
IL_001F:  stloc.0     
IL_0020:  br.s        IL_0029
IL_0022:  ldc.i4.0    
IL_0023:  newobj      10 00 00 0A 
IL_0028:  stloc.0     
IL_0029:  ldloc.0     
IL_002A:  ret         

<MyEmpty>d__0`1.System.Collections.IEnumerable.GetEnumerator:
IL_0000:  ldarg.0     
IL_0001:  call        11 00 00 0A 
IL_0006:  ret         

<MyEmpty>d__0`1.MoveNext:
IL_0000:  ldarg.0     
IL_0001:  ldfld       0F 00 00 0A 
IL_0006:  stloc.0     // CS$0$0000
IL_0007:  ldloc.0     // CS$0$0000
IL_0008:  ldc.i4.0    
IL_0009:  bne.un.s    IL_0012
IL_000B:  ldarg.0     
IL_000C:  ldc.i4.m1   
IL_000D:  stfld       0F 00 00 0A 
IL_0012:  ldc.i4.0    
IL_0013:  ret         

<MyEmpty>d__0`1.System.Collections.Generic.IEnumerator<TResult>.get_Current:
IL_0000:  ldarg.0     
IL_0001:  ldfld       12 00 00 0A 
IL_0006:  ret         

<MyEmpty>d__0`1.System.Collections.IEnumerator.Reset:
IL_0000:  newobj      System.NotSupportedException..ctor
IL_0005:  throw       

<MyEmpty>d__0`1.System.IDisposable.Dispose:
IL_0000:  ret         

<MyEmpty>d__0`1.System.Collections.IEnumerator.get_Current:
IL_0000:  ldarg.0     
IL_0001:  ldfld       12 00 00 0A 
IL_0006:  box         04 00 00 1B 
IL_000B:  ret         

<MyEmpty>d__0`1..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  ldarg.0     
IL_0007:  ldarg.1     
IL_0008:  stfld       0F 00 00 0A 
IL_000D:  ldarg.0     
IL_000E:  call        System.Environment.get_CurrentManagedThreadId
IL_0013:  stfld       0E 00 00 0A 
IL_0018:  ret         
MyEmpty:
IL_0000:ldc.i4.s FE
IL_0002:newobj 15 00 0A
IL_0007:stloc.0
IL_0008:ldloc.0
IL_0009:ret
d__0`1.System.Collections.Generic.IEnumerable.GetEnumerator:
IL_0000:调用System.Environment.get_CurrentManagedThreadId
IL_0005:ldarg.0
IL_0006:ldfld 0E 00 0A
IL_000B:bne.un.s IL_0022
IL_000D:ldarg.0
IL_000E:ldfld 0F 00 0A
IL_0013:ldc.i4.s FE
IL_0015:bne.un.s IL_0022
IL_0017:ldarg.0
IL_0018:ldc.i4.0
IL_0019:stfld 0F 00 0A
IL_001E:ldarg.0
IL_001F:stloc.0
ILU 0020:br.s ILU 0029
IL_0022:ldc.i4.0
IL_0023:newobj 10 00 0A
IL_0028:stloc.0
IL_0029:ldloc.0
IL_002A:ret
d__0`1.System.Collections.IEnumerable.GetEnumerator:
IL_0000:ldarg.0
IL_0001:拨打11 00 0A
IL_0006:ret
d__0`1.下一步:
IL_0000:ldarg.0
IL_0001:ldfld 0F 00 0A
IL_0006:stloc.0//CS$0$0000
IL_0007:ldloc.0//CS$0$0000
IL_0008:ldc.i4.0
IL_0009:bne.un.s IL_0012
IL_000B:ldarg.0
IL_000C:ldc.i4.m1
IL_000D:stfld 0F 00 0A
IL_0012:ldc.i4.0
IL_0013:ret
d__0`1.System.Collections.Generic.IEnumerator.get_Current:
IL_0000:ldarg.0
IL_0001:ldfld 12 00 0A
IL_0006:ret
d__0`1.System.Collections.IEnumerator.Reset:
IL_0000:newobj系统。不支持异常..ctor
IL_0005:投掷
d__0`1.System.IDisposable.Dispose:
IL_0000:ret
d__0`1.System.Collections.IEnumerator.get_Current:
IL_0000:ldarg.0
IL_0001:ldfld 12 00 0A
IL_0006:框04 00 1B
IL_000B:ret
d_uu0`1..ctor:
IL_0000:ldarg.0
IL_0001:调用系统对象
IL_0006:ldarg.0
IL_0007:ldarg.1
IL_0008:stfld 0F 00 0A
IL_000D:ldarg.0
IL_000E:调用System.Environment.get_CurrentManagedThreadId
IL_0013:stfld 0E 00 0A
IL_0018:ret

收益率中断
是C#中的一行,但是如果您查看生成的IL代码,它要复杂得多。数组是不可变的吗?从什么时候开始?特别是一个数组,用于特定类型的所有空实例。特别是,由于它是一个空数组,您不必担心它变脏,因为没有要变异的元素。数组不是不可变的,但它们的长度是不可变的,因此零元素数组实际上是不可变的。@SriramSakthivel抱歉,我指的是空数组,已编辑。@AlexSiepman,因为它正在为每个调用创建新实例,是的。如果您还添加了缓存所需的IL代码,那么这两者之间的比较如何?@Dirk关于这一点的重要说明-尽管它产生了更多的IL,但这并不是它的性能不如空数组的原因。主要的性能差异在于创建的对象数量。这与需要生成多少代码无关。@mot每次调用MyEmpty时,它都会创建该类的新实例。@Dirk True,但我没有另外说明。
yield
导致大量代码的事实并不是它性能不好的原因,而是流中实例化的对象的数量。@YuvalItzchakov是的,那完全是我的误解。我仍然坚持认为IL的数量对这里的性能没有任何意义,我怀疑这就是选择静态空数组的原因。内存分配方面的考虑更有意义。
EmptyEnumerable`1.get_Instance:
IL_0000:  volatile.   
IL_0002:  ldsfld      16 00 00 0A 
IL_0007:  brtrue.s    IL_0016
IL_0009:  ldc.i4.0    
IL_000A:  newarr      04 00 00 1B 
IL_000F:  volatile.   
IL_0011:  stsfld      16 00 00 0A 
IL_0016:  volatile.   
IL_0018:  ldsfld      16 00 00 0A 
IL_001D:  castclass   01 00 00 1B 
IL_0022:  ret
MyEmpty:
IL_0000:  ldc.i4.s    FE 
IL_0002:  newobj      15 00 00 0A 
IL_0007:  stloc.0     
IL_0008:  ldloc.0     
IL_0009:  ret         

<MyEmpty>d__0`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator:
IL_0000:  call        System.Environment.get_CurrentManagedThreadId
IL_0005:  ldarg.0     
IL_0006:  ldfld       0E 00 00 0A 
IL_000B:  bne.un.s    IL_0022
IL_000D:  ldarg.0     
IL_000E:  ldfld       0F 00 00 0A 
IL_0013:  ldc.i4.s    FE 
IL_0015:  bne.un.s    IL_0022
IL_0017:  ldarg.0     
IL_0018:  ldc.i4.0    
IL_0019:  stfld       0F 00 00 0A 
IL_001E:  ldarg.0     
IL_001F:  stloc.0     
IL_0020:  br.s        IL_0029
IL_0022:  ldc.i4.0    
IL_0023:  newobj      10 00 00 0A 
IL_0028:  stloc.0     
IL_0029:  ldloc.0     
IL_002A:  ret         

<MyEmpty>d__0`1.System.Collections.IEnumerable.GetEnumerator:
IL_0000:  ldarg.0     
IL_0001:  call        11 00 00 0A 
IL_0006:  ret         

<MyEmpty>d__0`1.MoveNext:
IL_0000:  ldarg.0     
IL_0001:  ldfld       0F 00 00 0A 
IL_0006:  stloc.0     // CS$0$0000
IL_0007:  ldloc.0     // CS$0$0000
IL_0008:  ldc.i4.0    
IL_0009:  bne.un.s    IL_0012
IL_000B:  ldarg.0     
IL_000C:  ldc.i4.m1   
IL_000D:  stfld       0F 00 00 0A 
IL_0012:  ldc.i4.0    
IL_0013:  ret         

<MyEmpty>d__0`1.System.Collections.Generic.IEnumerator<TResult>.get_Current:
IL_0000:  ldarg.0     
IL_0001:  ldfld       12 00 00 0A 
IL_0006:  ret         

<MyEmpty>d__0`1.System.Collections.IEnumerator.Reset:
IL_0000:  newobj      System.NotSupportedException..ctor
IL_0005:  throw       

<MyEmpty>d__0`1.System.IDisposable.Dispose:
IL_0000:  ret         

<MyEmpty>d__0`1.System.Collections.IEnumerator.get_Current:
IL_0000:  ldarg.0     
IL_0001:  ldfld       12 00 00 0A 
IL_0006:  box         04 00 00 1B 
IL_000B:  ret         

<MyEmpty>d__0`1..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  ldarg.0     
IL_0007:  ldarg.1     
IL_0008:  stfld       0F 00 00 0A 
IL_000D:  ldarg.0     
IL_000E:  call        System.Environment.get_CurrentManagedThreadId
IL_0013:  stfld       0E 00 00 0A 
IL_0018:  ret