C#6更新
现在在C#6中?.是一种语言功能:
?.
// C#1-5 propertyValue1 = myObject != null ? myObject.StringProperty : null; // C#6 propertyValue1 = myObject?.StringProperty;
以下问题仍然适用于旧版本,但是如果使用new ?.运算符开发新应用程序则更好。
原始问题:
我经常想访问可能为空对象的属性:
string propertyValue1 = null; if( myObject1 != null ) propertyValue1 = myObject1.StringProperty; int propertyValue2 = 0; if( myObject2 != null ) propertyValue2 = myObject2.IntProperty;
等等…
我经常使用它,因此我有一个摘要。
在以下情况下,可以通过内联将其缩短到某种程度:
propertyValue1 = myObject != null ? myObject.StringProperty : null;
但是,这有点笨拙,尤其是在设置许多属性或多个级别可以为空的情况下,例如:
propertyValue1 = myObject != null ? (myObject.ObjectProp != null ? myObject.ObjectProp.StringProperty) : null : null;
我真正想要的是??样式语法,该语法非常适合直接空类型:
??
int? i = SomeFunctionWhichMightReturnNull(); propertyValue2 = i ?? 0;
因此,我提出了以下建议:
public static TResult IfNotNull<T, TResult>( this T input, Func<T, TResult> action, TResult valueIfNull ) where T : class { if ( input != null ) return action( input ); else return valueIfNull; } //lets us have a null default if the type is nullable public static TResult IfNotNull<T, TResult>( this T input, Func<T, TResult> action ) where T : class where TResult : class { return input.IfNotNull( action, null ); }
这让我们有了以下语法:
propertyValue1 = myObject1.IfNotNull( x => x.StringProperty ); propertyValue2 = myObject2.IfNotNull( x => x.IntProperty, 0); //or one with multiple levels propertyValue1 = myObject.IfNotNull( o => o.ObjectProp.IfNotNull( p => p.StringProperty ) );
这简化了这些调用,但是我不确定是否要检查这种扩展方法- 它的确使代码更易于阅读,但以扩展对象为代价。这将出现在所有内容上,尽管我可以将其放在专门引用的名称空间中。
此示例是一个非常简单的示例,稍微比较复杂的一个示例是比较两个可为空的对象属性:
if( ( obj1 == null && obj2 == null ) || ( obj1 != null && obj2 != null && obj1.Property == obj2.Property ) ) ... //becomes if( obj1.NullCompare( obj2, (x,y) => x.Property == y.Property ) ...
以这种方式使用扩展的陷阱是什么?其他编码人员可能会感到困惑吗?这仅仅是滥用扩展名吗?
我想我这里真正想要的是编译器/语言扩展:
propertyValue1 = myObject != null ? myObject.StringProperty : null; //becomes propertyValue1 = myObject?StringProperty;
这将使复杂的情况变得容易得多:
propertyValue1 = myObject != null ? (myObject.ObjectProp != null ? myObject.ObjectProp.StringProperty) : null //becomes propertyValue1 = myObject?ObjectProp?StringProperty;
这仅适用于值类型,但您可以返回可为空的等效项:
int? propertyValue2 = myObject?ObjectProp?IntProperty; //or int propertyValue3 = myObject?ObjectProp?IntProperty ?? 0;
我们独立地提出了完全相同的扩展方法名称和实现:空传播扩展方法。因此,我们不认为这会造成混淆或滥用扩展方法。
我将用链接编写您的“多个级别”示例,如下所示:
propertyValue1 = myObject.IfNotNull(o => o.ObjectProp).IfNotNull(p => p.StringProperty);
Microsoft Connect上有一个现已关闭的错误,提示“?”。作为将执行此空传播的新C#运算符。来自C#语言团队的Mads Torgersen简要解释了为什么他们不实现它。