Гарантируется ли выполнение контрактов кода перед вызовом цепочечных конструкторов?

До того, как я начал использовать Контракты Кодекса, я иногда сталкивался с трудностями, связанными с проверкой параметров при использовании цепочки конструктора.

Это проще всего объяснить с помощью (надуманного) примера:

class Test
{
    public Test(int i)
    {
        if (i == 0)
            throw new ArgumentOutOfRangeException("i", i, "i can't be 0");
    }

    public Test(string s): this(int.Parse(s))
    {
        if (s == null)
            throw new ArgumentNullException("s");
    }
}

Я хочуTest(string) конструктор, чтобы связатьTest(int) конструктор, и для этого я используюint.Parse().

Конечно,int.Parse() не любит иметь нулевой аргумент, так что еслиs Значение null будет выдано до того, как я достигну строк проверки:

if (s == null)
    throw new ArgumentNullException("s");

что делает эту проверку бесполезной.

Как это исправить? Ну, я иногда делал это:

class Test
{
    public Test(int i)
    {
        if (i == 0)
            throw new ArgumentOutOfRangeException("i", i, "i can't be 0");
    }

    public Test(string s): this(convertArg(s))
    {
    }

    static int convertArg(string s)
    {
        if (s == null)
            throw new ArgumentNullException("s");

        return int.Parse(s);
    }
}

Это немного неудобно, и трассировка стека не идеальна в случае сбоя, но работает.

Теперь вместе с Code Contracts, поэтому я начинаю их использовать:

class Test
{
    public Test(int i)
    {
        Contract.Requires(i != 0);
    }

    public Test(string s): this(convertArg(s))
    {
    }

    static int convertArg(string s)
    {
        Contract.Requires(s != null);
        return int.Parse(s);
    }
}

Все хорошо. Работает нормально. Но потом я обнаруживаю, что могу сделать это:

class Test
{
    public Test(int i)
    {
        Contract.Requires(i != 0);
    }

    public Test(string s): this(int.Parse(s))
    {
        // This line is executed before this(int.Parse(s))
        Contract.Requires(s != null);
    }
}

И тогда, если я сделаюvar test = new Test(null),Contract.Requires(s != null) выполняетсядо this(int.Parse(s)), Это означает, что я могу покончить сconvertArg() проверить в целом!

Итак, к моим актуальным вопросам:

Задокументировано ли это поведение где-нибудь?Могу ли я рассчитывать на такое поведение при написании контрактов кода для подобных конструкторов?Есть ли какой-то другой способ, которым я должен подходить к этому?

Ответы на вопрос(1)

Ваш ответ на вопрос