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;