When compiling code which uses code contracts, I have a very strange error I don't understand.
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(
this.isSubsidiary ||
this.parentCompanyId == default(Guid));
}
fails with the following error:
Malformed contract. Found Invariant after assignment in method '
.ObjectInvariant'.
If the code is modified like this:
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(
this.isSubsidiary ||
this.parentCompanyId == Guid.Empty);
// Noticed the Guid.Empty instead of default(Guid)?
}
it compiles well.
What's wrong with my default(Guid)
?
Сгенерированный для этого IL:
Console.WriteLine("{0}, {1}", default(Guid), Guid.Empty);
это:
.locals init (
[0] valuetype [mscorlib]System.Guid CS$0$0000)
L_0000: nop
L_0001: ldstr "{0}, {1}"
L_0006: ldloca.s CS$0$0000
L_0008: initobj [mscorlib]System.Guid
L_000e: ldloc.0
L_000f: box [mscorlib]System.Guid
L_0014: ldsfld valuetype [mscorlib]System.Guid [mscorlib]System.Guid::Empty
L_0019: box [mscorlib]System.Guid
L_001e: call void [mscorlib]System.Console::WriteLine(string, object, object)
Что соответствует чему-то вроде:
Guid CS$0$0000 = new Guid();
Console.WriteLine("{0}, {1}", CS$0$0000, Guid.Empty);
Code Contracts работает непосредственно на IL, поэтому он думает, что вы написали что-то вроде вторая версия. Переписчик говорит, что вам не разрешено назначать переменные до контрактов, поэтому выдает ошибку.
Однако это странно, потому что, хотя это не работает:
var x = new Guid();
Contract.Invariant(
this.isSubsidiary ||
this.parentCompanyId == x);
это работает, но это явно "назначение перед инвариантом"!
var x = Guid.Empty;
Contract.Invariant(
this.isSubsidiary ||
this.parentCompanyId == x);
Я думаю, что они на самом деле модифицировали средство проверки, чтобы разрешить некоторые подобные назначения (для простоты использования), но они не разрешили все случаи... намеренно это или нет, мне неизвестно.
Я бы сообщил об этом на форуме Code Contracts, возможно, это ошибка.