Как я могу показать, что метод никогда не вернет значение null (дизайн по контракту) в С#

У меня есть метод, который никогда не возвращает нулевой объект. Я хочу пояснить, чтобы пользователям моего API не приходилось писать такой код:

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

Как я могу показать это намерение?


person StackUnderflow    schedule 27.01.2009    source источник
comment
Кроме того, нет никакого способа узнать, можете ли вы вообще вернуть ненулевой объект (если только это не структура). Может быть, вы хотите вернуть структуру?   -  person Trap    schedule 27.01.2009
comment
Теперь стандартизировано как Contract.Ensures(Contract.Result<T>() != null) в контрактах кода. постусловия в пространстве имен System.Diagnostics.Contracts. По первой приведенной выше ссылке я получаю эту ссылку для скачивания.   -  person ToolmakerSteve    schedule 17.04.2020


Ответы (9)


К сожалению, в С# нет встроенного способа.

Вы можете задокументировать этот факт, но это не будет автоматически проверено.

Если вы используете resharper, то его можно настроить для правильной проверки, когда метод помечен атрибутом [NotNull].

В противном случае вы можете использовать библиотеку Microsoft Contracts и добавить что-то похожее на следующее к вашему методу, но это довольно много лишнего словоблудия для такой простой аннотации.

Contract.Ensures(Contract.Result<string>() != null)

Spec# решил эту проблему, разрешив ! после типа, чтобы пометить его как ненулевой тип, например

string! foo

но Spec# можно использовать только для таргетинга на .NET2, и он был узурпирован библиотекой Code Contracts.

person Oliver Hallam    schedule 27.01.2009
comment
Э-э, но это неправильно... вы можете гарантировать, что метод не вернет null. Смотрите любой из других ответов... - person Robert P; 27.01.2009
comment
Использование структуры не помогает, если вы хотите вернуть ненулевую строку. Вы можете вернуть ненулевую структуру, содержащую строку, которая может быть нулевой, но чем это лучше? - person Oliver Hallam; 29.01.2009
comment
синтаксис неверен в вашем примере контрактов. Result должен быть вызовом метода: Contract.Result<string>() - person porges; 09.05.2010
comment
Теперь стандартизировано как Contract.Ensures(Contract.Result<T>() != null) в контрактах кода. постусловия в пространстве имен System.Diagnostics.Contracts. - person ToolmakerSteve; 17.04.2020

Если вы не используете тип, основанный на System.ValueType, я думаю, вам не повезло. Вероятно, лучше всего четко задокументировать это в комментарии XML/метаданных для функции.

person Jason Jackson    schedule 27.01.2009

Я не знаю, есть ли наилучшая практика для этого из API, поскольку я все равно буду программировать в обороне и проверять нуль как потребитель. Я думаю, что это все еще лучшая практика в этом случае, поскольку я склонен не доверять другому коду, чтобы он всегда делал правильные вещи.

person Brawndo    schedule 27.01.2009

Единственный способ с проверкой типов гарантировать, что объект C# никогда не вернет значение 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
    }
}

Приведенный выше пример не будет компилироваться. Если использование структуры приемлемо (она становится типом значения, передается по стеку, не может быть подклассом), то это может сработать для вас.

person Robert P    schedule 27.01.2009
comment
Обратите внимание, что структуры по умолчанию передаются по значению, а классы по умолчанию передаются по ссылке. Разница в том, что содержимое структуры сбрасывается в стек при передаче, в то время как для классов в стек сбрасывается только ссылка, что позволяет вам взаимодействовать с исходным объект, а не новую копию. Это можно переопределить с помощью ключевого слова ref, но тогда вы 1) должны помнить об использовании его в каждом месте, где вам не нужна копия, и 2) оно может снова быть нулевым, чего вы пытались избежать в первое место. - person Thought; 11.04.2014

Мне нравится думать об этом наоборот: если моя функция может возвращать нулевое значение, мне лучше убедиться, что пользователь функции знает об этом.

person Joel Coehoorn    schedule 27.01.2009

Если у ваших пользователей есть исходный код, использующий стандартный API-интерфейс проектирования по контракту, например: http://www.codeproject.com/KB/cs/designbycontract.aspx может прояснить ситуацию.

В противном случае лучше всего использовать документацию.

person JoshBerke    schedule 27.01.2009

Либо хорошо задокументируйте это (возможно, с помощью стандартной системы документации .NET), либо вам придется использовать какой-либо контрактный API. Вот некоторые из них: http://geekswithblogs.net/Podwysocki/archive/2008/01/22/118770.aspx http://www.codeproject.com/KB/cs/designbycontract.aspx

person Stefano Driussi    schedule 27.01.2009

Вы можете включить метод Debug.Assert(). Хотя это, конечно, не приведет к принудительному выполнению условия, должно быть ясно (вместе с документацией), что нулевое значение неприемлемо.

person Otis    schedule 27.01.2009

Задокументируйте его и предоставьте исходный код.

person Tundey    schedule 27.01.2009