Гарантируется ли выполнение контрактов кода перед вызовом цепочечных конструкторов?
До того, как я начал использовать Контракты Кодекса, я иногда сталкивался с трудностями, связанными с проверкой параметров при использовании цепочки конструктора.
Это проще всего объяснить с помощью (надуманного) примера:
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()
Безразлично»не нравится иметь нулевой аргумент, так что если с Значение 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()
тест в целом!
Итак, к моим актуальным вопросам:
Задокументировано ли это поведение где-нибудь?Могу ли я рассчитывать на такое поведение при написании контрактов кода для подобных конструкторов?Есть ли какой-то другой способ, которым я должен подходить к этому?