一尘不染

使用此(基于扩展方法)速记的可能陷阱

c#

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;

阅读 289

收藏
2020-05-19

共1个答案

一尘不染

我们独立地提出了完全相同的扩展方法名称和实现:空传播扩展方法。因此,我们不认为这会造成混淆或滥用扩展方法。

我将用链接编写您的“多个级别”示例,如下所示:

propertyValue1 = myObject.IfNotNull(o => o.ObjectProp).IfNotNull(p => p.StringProperty);

Microsoft
Connect上
有一个现已关闭的错误,提示“?”。作为将执行此空传播的新C#运算符。来自C#语言团队的Mads
Torgersen简要解释了为什么他们不实现它。

2020-05-19