方法调用中的C#null检查链

时间:2017-03-31 02:50:37

标签: c# null-check

我想下面的方法调用链。

void DoSomething()
{
    ObjectA a = CreateA();
    if (a != null)
    {
        a.Foo();
    }
}

ObjectA CreateA()
{
    ObjectB b = CreateB();
    if (b != null)
    {    
        ObjectA a = b.ToA();
        return a;
    }
    return null;
}

如果方法调用深度变深,则空检查将更加重叠。 对此有什么好的解决方案吗?

修饰

我更改了示例代码。它无法解决我将CreateA更改为构造函数的问题。 问题是只有不必要的空检查链接重叠。

void SetImage()
{
    UISprite image = GetSprite();
    if (image  != null)
    {
        image.spriteName = "hat";
    }
}

UISprite GetSprite()
{
    UISprite image = GetComponent<UISprite>();
    if (image  != null)
    {   
        image.width = 100;
        image.height = 100;
        return image;
    }
    return null;
}

4 个答案:

答案 0 :(得分:7)

从C#6.0开始,您可以使用Null-Conditional Operator,这可以隐式进行空检查:

var result = possiblyNull?.MethodThatCanReturnNull()?.SomeProperty;

如果链中的任何元素产生null,则此构造将生成null结果。

答案 1 :(得分:2)

你可以做到

void DoSomething()
{
    CreateA()?.Foo();
}

ObjectA CreateA()
{
    return CreateB()?.ToA();
}

如果你不能使用C#6,你的另一种方法是不返回空值,使用空对象,你永远不必处理空检查(但你仍然可以检查是否有空对象)

答案 2 :(得分:0)

如果您使用的是C#6.0或更高版本,则可以使用Null条件运算符轻松解决此问题。

请参阅此链接

https://msdn.microsoft.com/en-au/library/dn986595.aspx?f=255&MSPPError=-2147217396&cs-save-lang=1&cs-lang=csharp#code-snippet-1

答案 3 :(得分:0)

因此,假设您(或其他人)不能使用空条件运算符,是否有充分的理由使用这种方法模式创建对象而不是构造对象的构造函数?构造函数保证不返回null。

看起来你有一些转换或嵌套对象层次结构,但没有继承heirarchy,你可以回到多态。也许像AutoMapper这样的工具可以用于以一致的方式编码这些ToX()方法吗?

我不确定这会是多么“嵌套”。您的CreateB()方法看起来与您的CreateA()代码完全相同。你不会最终得到一个“金字塔”,只是很多相同的方法。

ObjectB CreateB()
    {
        ObjectC c = CreateC();
        if (c != null)
        {    
            ObjectB b = c.ToB();
            return b;
        }
        return null;
    }

大多数情况下,您在不控制所有类的环境中执行此操作。在这种情况下,编写自己的转换函数或AutoMapper(真的,值得花时间)是最好的方法。但是,如果你拥有类层次结构,你可以实现一个抽象类,它将为你完成大部分繁重的工作。但老实说,如果我有一个非常好的理由(比我只是想与人交谈),我只会写这样的东西。我包含这个来演示如果你只使用一个构造函数,那么生命会有多么简单,但是保证不会返回null;

public abstract class MyAbstractObject<Tobj> where TObj: MyAbstractObject, new()
{
    public static MyAbstractObject CreateObject()
    {
        Tobj subOb = new TObj();
        MyAbstractObject parent = subOb.ToObject();
        return parent;
    }
    public virtual TObj ToObject()
    {
        return CreateObject();
    }
}

public class ObjectD : MyAbstractObject<ObjectC> { }
public class ObjectC : MyAbstractObject<ObjectB> { }
public class ObjectB : MyAbstractObject<ObjectA> { }
public class ObjectA : MyAbstractObject<ObjectA>
{
    public override TObj ToObject()
    {
        return this;
    }
}

static void Main()
{
    ObjectA a = ObjectD.CreateObject();
}