如何在C#中表明一个方法永远不会返回null(契约设计)

10

我有一个不会返回空对象的方法。我想让它更明确,这样我的API用户就不必编写像下面这样的代码:

if(Getxyz() != null)
{
  // do stuff
}

我该如何展示这个意图?


此外,除非它是一个结构体,否则无法知道是否可以返回一个非空对象。也许你想返回一个结构体? - Trap
现在已经标准化为Contract.Ensures(Contract.Result<T>() != null),位于System.Diagnostics.Contracts命名空间Code Contracts - postconditions中。从上面的第一个链接中,我可以获得此链接进行下载 - ToolmakerSteve
9个回答

10
很遗憾,C#中没有内置的方法来实现这一点。
您可以记录这个事实,但这不会自动检查。
如果您正在使用resharper,那么可以在方法标记为[NotNull]属性时正确设置它进行检查。
否则,您可以使用Microsoft Contracts库,并将类似以下内容添加到您的方法中,但对于如此简单的注释来说,这是相当多的额外冗长语言。
Contract.Ensures(Contract.Result<string>() != null)

Spec#通过允许在类型后面加上!来标记它为非空类型,从而解决了这个问题,例如
string! foo

但是Spec#只能用于目标.NET2,并且已被Code Contracts库取代。


哎呀,但是这是错误的...您无法保证一个方法不会返回 null。请参考其他答案... - Robert P
3
如果你想要返回一个非空字符串,使用结构体并不能帮助你。你可以返回一个非空的结构体,其中包含可能为空的字符串,但这有什么好处呢? - Oliver Hallam
你的Contracts示例语法有误。Result应该是一个方法调用:Contract.Result<string>() - porges
现在已经标准化为Contract.Ensures(Contract.Result<T>() != null),位于System.Diagnostics.Contracts命名空间Code Contracts - postconditions中。 - ToolmakerSteve

6

除非您正在使用基于System.ValueType的类型,否则我认为您会没有运气。最好在函数的XML/metadata注释中明确记录这一点。


2

我不知道在API中是否有最佳实践,因为作为使用者,我仍然会进行防御性编程并检查null。在这种情况下,我认为这仍然是最佳实践,因为我倾向于不相信其他代码总是做正确的事情。


2

确保 C# 对象从不返回 null 的唯一类型检查的方法是使用结构体。结构体可以具有包含空值的成员,但它们本身永远不能为 null。

所有其他 C# 对象都可以为空。

示例代码:

public struct StructExample
{
    public string Val;
}

public class MyClass
{
    private StructExamle example;

    public MyClass()
    {
        example = null; // will give you a 'Cannot convert to null error
    }

    public StructExample GetXyz()
    {
        return null; // also gives the same error
    }
}

上面的例子无法编译。如果使用结构体是可接受的(它变成了值类型,在堆栈上传递,不能被子类化),那么这可能适合您。


请注意,结构体默认情况下是按值传递的,而类默认情况下是按引用传递的。它们之间的区别在于传递时结构体的内容被转储到堆栈上,而对于类只有一个引用被放置在堆栈上,允许您与原始对象交互而不是新副本。这可以通过使用"ref"关键字来覆盖,但是这样做需要记住在每个不想要复制的地方使用它,并且它可能再次为null,这正是您一开始想要避免的。 - Thought

1
我喜欢从另一个角度来思考:如果我的函数可能返回空值,那么我最好确保函数的使用者知道这一点。

0

0

0
你可以使用Debug.Assert()方法。虽然这并不能强制执行条件,但它应该能够清楚地表明(连同文档),null值是不可接受的。

0

对其进行文档化并提供源代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接