Null合并运算符IList,Array,Enumerable.Empty in foreach

IDa*_*der 22 .net c# collections null-coalescing-operator

这个问题中,我发现了以下内容:

int[] array = null;

foreach (int i in array ?? Enumerable.Empty<int>())  
{  
    System.Console.WriteLine(string.Format("{0}", i));  
}  
Run Code Online (Sandbox Code Playgroud)

int[] returnArray = Do.Something() ?? new int[] {};
Run Code Online (Sandbox Code Playgroud)

... ?? new int[0]
Run Code Online (Sandbox Code Playgroud)

在一个NotifyCollectionChangedEventHandler我想申请Enumerable.Empty如此:

foreach (DrawingPoint drawingPoint in e.OldItems ?? Enumerable.Empty<DrawingPoint>())
    this.RemovePointMarker(drawingPoint);
Run Code Online (Sandbox Code Playgroud)

注意: OldItems 属于该类型 IList

它给了我:

接线员'??' 不能应用于'System.Collections.IList'类型的操作数System.Collections.Generic.IEnumerable<DrawingPoint>

然而

foreach (DrawingPoint drawingPoint in e.OldItems ?? new int[0])
Run Code Online (Sandbox Code Playgroud)

foreach (DrawingPoint drawingPoint in e.OldItems ?? new int[] {})
Run Code Online (Sandbox Code Playgroud)

工作得很好.

这是为什么?
为什么IList ?? T[]工作但IList ?? IEnumerable<T>不工作?

ang*_*son 20

使用此表达式时:

a ?? b
Run Code Online (Sandbox Code Playgroud)

然后b要么必须是相同的类型a,要么必须隐式地转换为该类型,带引用意味着它必须实现或继承任何类型a.

这些工作:

SomethingThatIsIListOfT ?? new T[0]
SomethingThatIsIListOfT ?? new T[] { }
Run Code Online (Sandbox Code Playgroud)

因为T[] 一个IList<T>,阵列类型实现该接口.

但是,这不起作用:

SomethingThatIsIListOfT ?? SomethingThatImplementsIEnumerableOfT
Run Code Online (Sandbox Code Playgroud)

因为表达式的a类型将是类型,并且编译器显然无法保证SomethingThatImplementsIEnumerableOfT也实现IList<T>.

你将不得不施放两个中的一个,以便你有兼容的类型:

(IEnumerable<T>)SomethingThatIsIListOfT ?? SomethingThatImplementsIEnumerableOfT
Run Code Online (Sandbox Code Playgroud)

现在表达式的类型是IEnumerable<T>,??操作员可以做它的事情.


"表达式的类型将是类型a"有点简化,规范中的全文如下:


表达式的类型a ?? b取决于操作数上可用的隐式转换.按优先顺序,类型a ?? bA0,A或,或者B,Aa的类型(如果a有类型),Bb(提供b有类型)的类型,并且if 是可空类型A0的基础类型或者其他.具体来说,处理如下: AAAa ?? b

  • 如果A存在且不是可空类型或引用类型,则发生编译时错误.
  • 如果b是动态表达式,则结果类型是动态的.在运行时,a首先进行评估.如果a不是null,a则转换为动态类型,这就成了结果.否则,b进行评估,结果成为结果.
  • 否则,如果A存在并且是可空类型并且存在来自bto 的隐式转换A0,则结果类型为A0.在运行时,a首先进行评估.如果a不是null,a则打开包装A0,它就成了结果.否则,b将进行评估并转换为类型A0,并将其作为结果.
  • 否则,如果A存在且存在来自bto 的隐式转换A,则结果类型为A.在运行时,a首先进行评估.如果a不为null,则a成为结果.否则,b将进行评估并转换为类型A,并将其作为结果.
  • 否则,如果b存在类型B并且存在来自ato 的隐式转换B,则结果类型为B.在运行时,a首先进行评估.如果a不是null,a则解包为键入A0(如果A存在并且可以为空)并转换为类型B,并且它将成为结果.否则,b评估并成为结果.
  • 否则,a并且b不兼容,并发生编译时错误.

  • 除了'新T [0]`,我不知道,当然可能有一些我不知道的东西. (2认同)
  • 无论是`new T []`还是`new List <T>()`都可以做到这一点,正如@LasseVågsætherKarlsen所说的那样 (2认同)
  • @IDarkCoder有[Array.Empty](https://docs.microsoft.com/en-us/dotnet/api/system.array.empty?view=netframework-4.7.2),它通常优于`new T [0]`因为后者总是构造一个新的数组实例,而Array.Empty重用它. (2认同)

归档时间:

查看次数:

1095 次

最近记录:

6 年,11 月 前