我经常在我的代码中使用null传播运算符,因为它给了我更多可读代码,特别是在长查询中我不必对每个使用的类进行空值检查.
以下代码抛出一个编译错误,我们不能在lambda中使用null传播运算符.
var cnt = humans.AsQueryable().Count(a => a.House?[0].Price == 5000);
Run Code Online (Sandbox Code Playgroud)
错误 :
错误CS8072表达式树lambda可能不包含空传播运算符.
C#如果真的不能做任何其他事情,可以轻松地将上面的代码转换为代码到下面的代码!
var cnt = humans.AsQueryable().Count(a => a.House != null && a.House[0].Price == 5000);
Run Code Online (Sandbox Code Playgroud)
我很好奇为什么C#什么也不做,只是抛出一个编译器错误?
为了彻底解释,这个问题已经彻底改革.
我注意到C#6.0中空传播运算符的限制似乎很差,因为你无法针对已经传播的对象调用属性设置器(尽管你可以针对已经传播的对象调用属性getter) .正如您将从生成的IL (我已反映到C#中)看到的那样,没有任何东西可以限制使用空传播调用属性设置器的能力.
首先,我创建了一个简单的类,包括Java样式的Get/Set方法和具有公共getter/setter访问权限的属性.
public class Person
{
public Person(string name, DateTime birthday)
{
Name = name;
}
public string Name { get; set; }
public void SetName(string name)
{
Name = name;
}
public string GetName()
{
return Name;
}
}
Run Code Online (Sandbox Code Playgroud)
我已经在下面的测试类中测试了空传播的能力.
public class Program
{
public static void Main(string[] args)
{
Person person = new Person("Joe Bloggs", DateTime.Parse("01/01/1991"));
// This line doesn't work - see documented error below
person?.Name = "John Smith"; …Run Code Online (Sandbox Code Playgroud) 我偶然发现了一个有趣的网站,其中解决了C#6.0的一些新的(提议的)功能.您可以在这里阅读:可能的C#6.0功能.
我觉得特别有趣的是monadic null检查(也称为null-propagation操作符?).根据网站,以下声明
var bestValue = points?.FirstOrDefault()?.X ?? -1;
Run Code Online (Sandbox Code Playgroud)
包含monadic null检查,目前使用这段代码实现:
if (points != null)
{
var next = points.FirstOrDefault();
if (next != null && next.X != null) return next.X;
}
return -1;
Run Code Online (Sandbox Code Playgroud)
我的第一眼就是,嘿,这里写的是什么?但在查看"旧"代码后,我开始喜欢它了.
但是,我也开始提出一些问题,我想问一下.
该运算符如何处理泛型类型?而且,它如何处理无约束的泛型类型?例如,考虑一下
var resultAfterNullCheck = x?.Y;
Run Code Online (Sandbox Code Playgroud)
如果这里的类型Y用引用类型,非可空值类型和可空值类型实例化,那么就没有任何合理的做法(因为我不知道该做什么,因为我根本不知道该怎么做).那么是否会返回默认值?或者它会抛出错误?
在查看站点提供的示例(以及我在上面复制的示例)时,我假设null-propagation运算符的一个主要好处是它只会评估语句一次.然而(也许是由于我对CLR的了解不足),我很好奇它是如何进行的.
对我来说,第一个评估(如果points等于null)应该触发扩展方法FirstOrDefault()在points不为null时触发,然后将返回类型的evalation设置为null或者不是,否则,X将是回.那么这些实际上是三个评估合二为一?或者我不正确地理解它?这会影响执行速度吗?
换句话说,什么会更快,执行空检查的旧方法,或这个新的可爱运算符?我将在Visual Studio 2015下载完成后立即进行一些研究来检查这一点...但这需要一点耐心......
对这种新的操作员类型有什么想法吗?它真的还是一个提议的,或者我们真的可以期望使用这个新的monadic null检查吗?
编辑
正如Matthew Watson提供了一篇很好的MSDN讨论这个(以及更多)主题的文章,我很好奇它是否提到了我之前关于无约束泛型的问题以及这个算子如何处理它.不幸的是,我还没有找到答案.虽然我认为程序员应该试图阻止使用无约束泛型,但我仍然可以想象这有时是不可行的.如果是这样的话,重新设计是否真的有必要?
试图制作Feature通用然后突然编译说
接线员'?' 不能应用于'T'类型的操作数
这是代码
public abstract class Feature<T>
{
public T Value
{
get { return GetValue?.Invoke(); } // here is error
set { SetValue?.Invoke(value); }
}
public Func<T> GetValue { get; set; }
public Action<T> SetValue { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
可以使用此代码
get
{
if (GetValue != null)
return GetValue();
return default(T);
}
Run Code Online (Sandbox Code Playgroud)
但我想知道如何修复那个漂亮的C#6.0单线程.
新的C#6.0空条件运算符是一种方便的工具,用于编写更简洁,更简单的代码.假设有一个客户数组,那么如果customers使用此方法为空,则可以获取null而不是长度(来自MSDN的示例):
int? length = customers?.Length;
Run Code Online (Sandbox Code Playgroud)
同样地,您可以使用以下方法获取null而不是客户:
Customer first = customers?[0];
Run Code Online (Sandbox Code Playgroud)
对于更精细的表达式,如果customers为null,则第一个客户为null,或者第一个客户的Orders对象为null,则返回null:
int? count = customers?[0]?.Orders?.Count();
Run Code Online (Sandbox Code Playgroud)
但是,有一个有趣的情况是不存在的客户,零条件运算符似乎没有解决.我们在上面看到覆盖了一个空客户,即customers数组中的条目是否为空.但这与不存在的客户截然不同,例如5在3元素阵列中查找客户或n在0元素列表中查找客户.(请注意,同样的讨论也适用于字典查找.)
在我看来,零条件运算符专注于否定NullReferenceException的影响; IndexOutOfRangeException或KeyNotFoundException独自暴露,在角落里畏缩,需要自生自灭!我提出,在零条件运算符的精神下,它应该能够处理这些情况......这导致了我的问题.
我错过了吗?null条件是否提供了真正涵盖此表达式的任何优雅方式......
customers?[0]?.Orders?.Count();
Run Code Online (Sandbox Code Playgroud)
......没有第0个元素的时候?
阅读了很多关于Null传播算子的内容?.,我没有回答它是否有助于以下场景.
抛出的代码:
int[] values = null;
foreach ( var i in values ) // Throws since values is null.
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
为了使其工作,我必须null在访问values变量之前添加一个检查.
很可能上述代码超出了Null传播运算符的设计考虑范围.不过,可以肯定的是,我不得不问.
我的问题:
尝试null在foreach循环中访问集合时,Null传播运算符是否有用?
假设我有一个具有类型属性的类Dictionary<string,string>,可以为null.
这会编译,但调用TryGetValue()可能会NullRef在运行时抛出异常:
MyClass c = ...;
string val;
if(c.PossiblyNullDictionary.TryGetValue("someKey", out val)) {
Console.WriteLine(val);
}
Run Code Online (Sandbox Code Playgroud)
所以我添加一个空传播运算符来防范空值,但这不会编译:
MyClass c = ...;
string val;
if( c.PossiblyNullDictionary ?. TryGetValue("someKey", out val) ?? false ) {
Console.WriteLine(val); // use of unassigned local variable
}
Run Code Online (Sandbox Code Playgroud)
是否有一个实际的用例,val在if块中未初始化,或者编译器是否只是不能推断出这个(以及为什么)?
更新:最干净的(?)解决方法^ H ^ H ^ H ^ H ^ H修复此问题:
MyClass c = ...;
string val = null; //POW! initialized.
if( c.PossiblyNullDictionary ?. TryGetValue("someKey", out val) ?? false ) { …Run Code Online (Sandbox Code Playgroud) 老路
int? myFavoriteNumber = 42;
int total = 0;
if (myfavoriteNumber.HasValue)
total += myFavoriteNumber.Value *2;
Run Code Online (Sandbox Code Playgroud)
新方法?
int? myFavoriteNumber = 42;
total += myFavoriteNumber?.Value *2; //fails
Run Code Online (Sandbox Code Playgroud) c# nullable null-propagation-operator null-conditional-operator
我最喜欢的一个C#功能是CS6中的" 零传播 ".
这为我们许多人清理了很多代码.
我遇到的情况似乎不太可能.我不知道为什么我虽然null传播只是一些编译器魔术,它为我们做了一些空检查,允许我们保持更清晰的代码.
在挂钩事件的情况下..
public override void OnApplyTemplate()
{
_eventStatus = base.GetTemplateChild(PART_EventStatus) as ContentControl;
// This not permitted and will not compile
_eventStatus?.IsMouseDirectlyOverChanged += EventStatusOnIsMouseDirectlyOverChanged;
// but this will work
if(_eventStatus != null) _eventStatus.IsMouseDirectlyOverChanged += EventStatusOnIsMouseDirectlyOverChanged;
base.OnApplyTemplate();
}
private void EventStatusOnIsMouseDirectlyOverChanged(object sender, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
throw new NotImplementedException();
}
Run Code Online (Sandbox Code Playgroud)
编译输出显示:
error CS0079: The event 'UIElement.IsMouseDirectlyOverChanged' can only appear on the left hand side of += or -=
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是 - 我对误传播的误解是什么?为什么这不是允许的语法?
我有以下代码:
await _user?.DisposeAsync();
Run Code Online (Sandbox Code Playgroud)
Visual Studio 突出显示此代码,说“可能的 NullReferenceException”
顺便说一句,没有await Visual Studio不显示此警告为什么NullReferenceException在这里可能?
c# exception nullreferenceexception async-await null-propagation-operator