强制方法不返回null

时间:2018-01-10 08:39:06

标签: c# oop null nullreferenceexception

8年前问Here问题,但我认为应该有一种方法(新模式,新设计,新架构或其他任何东西。)来强制执行方法不会返回null。

如您所知,在方法中返回null会产生一些影响,对我来说很重要的是:

在Consuming-Side和可理解的语义中处理null,如:

方法:

public ClassName Do()
{
    ...
    return null;
}

调用Do()之类的(注意评论也是):

var objVal = Do(); 
//Accessing property of ClassName raised exception
var pnVal = objVal.PropName;//Exception id objVal is null

//But I should handle if it is not null then do anything I want
if(objVal!= null)
{
    //Do something
}
通过上述方式在产品上出现许多问题后,我得出了这个结论,概括了所有方法遵循模式可读,清晰和防止模糊语义。

所以一个非常基本的方法是使用Struct类型,因为结构不能为null,如果返回类型的方法是结构,那么它们不能返回null,我们知道这在编译时< / strong>不在运行时。

所以我实现了上面的方法,如:

1-为方法制作DTO outin,在这种情况下仅为out

public struct Do_DTO_Out
{
    public ClassName Prop1 { get; set; }
    public bool IsEmpty
    {
        get
        {
            return Prop1 == null;
        }
    }

    public static Do_DTO_Out Empty
    {
        get
        {
            return new Do_DTO_Out() { Prop1 = null };
        }
    }
}

2- Do方法应该是:

public Do_DTO_Out Do()
{
    try
    {
        return manipulatedObj;
    }
    catch (Exception exp)
    {

    }
    return Do_DTO_Out.Empty;
}

3-消费方:

var objVal = Do();
if (!objVal.IsEmpty)
    //Do something

struct是最好的方法吗?是否值得更改所有方法并为每个方法创建DTO inout(我认为是这样)。

有没有更好的方法来做到这一点,任何想法,帮助,答案都会得到真正的赞赏。

3 个答案:

答案 0 :(得分:3)

'带有属性检查的结构'转换的'引用类型'对我来说似乎没用。它还需要对您的意图有深入了解,而参考类型无效检查对于以后阅读它的人来说非常明显。

我认为code contracts可能适合你。它为您提供编译时静态分析和运行时检查。只要确保你有合适的合同作为后期条件:

public ClassName Do()
{
    ...

    object returnValue = null;

    Contract.Ensures(returnValue != null);

    return returnValue;
}

答案 1 :(得分:1)

假设值永远不会是null,否则if是不可避免的(但对于单个方法调用,您现在可以编写Do()?.DoSomething())。

如果您可以引入代码合同(请参阅Patrick's answer),那么我完全同意Patrick的意见,您应该同意它们。如果它不可行(因为您的代码库已经太大了,或者您正在针对他们不受支持的环境),那么我首先使用断言:

var obj = Do();
Debug.Assert(obj != null);

// Use obj...

然而,我们将此责任转移到呼叫点,这可能是乏味的。如果你想让这个接口显式化,那么你可以按照你的想法使用某个结构但在调用点抛出异常(错误在哪里):

public NotNullable<SomeClass> Do() { }

NotNullable<T>定义为:

public struct NotNullable<T> where T : class
{
    public NotNullable(T value)
    {
        Value = value ?? throw new ArgumentNullException(nameof(value));
    }

    public T Value { get; }
}

但是,我不想在呼叫点明确访问.Value,然后我将其透明添加:

public static implicit operator T(NotNullable<T> rhs)
    => rhs.Value;

现在来电者可以:

MyClass obj = Do();
obj.DoSomthing();

在创建对象时抛出正确的异常(在运行时,不幸)。使用[Conditional("DEBUG")]时,您可以排除对发布版本的检查,该版本具有类似于Debug.Assert()的行为和最小(但仍然存在)的开销。

请注意,仅当您希望直接在其签名中记录接口方法有关此约束时,这才有意义。如果您对此不感兴趣,请尽量保持简单:

public SomeClass Do()
{
    MyClass somevalue = ...

    // ...

    return NotNull(somevalue);
}

其中NotNull()是静态方法定义某处并使用using static导入,甚至是object的扩展方法,称为return somevalue.NotNull()

我不是特别喜欢这种方法,因为我觉得Debug.Assert()在这些情况下已经足够了,但这只是我的观点。当然,也许有一天我们会在C#中使用Nullable Reference Types,然后我们将获得编译时强制执行(object?或反过来object!)。

答案 2 :(得分:0)

返回null是一个坏习惯-更好地实现 NullObject Design Pattern