2010-08-29 7 views
9

Beim kompilieren Code, der Code-Verträge verwendet, habe ich einen sehr seltsamen Fehler, den ich nicht verstehe.Warum Vertrag ist falsch, wenn Sie Standard (Typ) verwenden?

[ContractInvariantMethod] 
private void ObjectInvariant() 
{ 
    Contract.Invariant(
     this.isSubsidiary || 
     this.parentCompanyId == default(Guid)); 
} 

schlägt mit dem folgenden Fehler:

Malformed contract. Found Invariant after assignment in method '<ProjectName>.ObjectInvariant'.

Wenn der Code wie folgt geändert:

[ContractInvariantMethod] 
private void ObjectInvariant() 
{ 
    Contract.Invariant(
     this.isSubsidiary || 
     this.parentCompanyId == Guid.Empty); 
     // Noticed the Guid.Empty instead of default(Guid)? 
} 

es gut kompiliert.

Was ist los mit meinem default(Guid)?

+0

So weit ich weiß: public static readonly Guid Empty; und Standard (Guid) oder neue Guid() ist das gleiche Ich weiß nicht, warum es hier nicht funktioniert. – abhishek

+0

Ich bin auch darauf gestoßen. Kurioserweise hat default (int) nicht den gleichen Effekt. –

+0

@Can Gencer: Ich denke, das wird erwartet, wenn Sie die Antwort von Porges lesen. Für 'default (Guid) 'entspricht die IL' Guid something = new Guid() ', also gibt es einen Aufruf an eine Methode (Konstruktor). Stattdessen entspricht 'default (int)' nicht 'int etwas = new int()', es ergibt keinen Sinn. Deshalb beschwert sich der Compiler im Fall von "int" nicht. –

Antwort

6

Die IL hierfür erzeugt:

Console.WriteLine("{0}, {1}", default(Guid), Guid.Empty); 

ist:

.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) 

, die wie etwas entspricht:

Guid CS$0$0000 = new Guid(); 
Console.WriteLine("{0}, {1}", CS$0$0000, Guid.Empty); 

-Code Verträge direkt auf dem IL funktioniert, so dass er denkt Du hast so etwas wie die zweite Version geschrieben. Der Redwriter sagt, dass es nicht erlaubt ist, Variablen vor den Verträgen zuzuweisen, daher gibt es einen Fehler.

Dies ist jedoch seltsam, denn während das nicht funktioniert:

var x = new Guid(); 
Contract.Invariant(
    this.isSubsidiary || 
    this.parentCompanyId == x); 

dies tut, aber es ist eindeutig eine „Zuordnung vor Invariant“!

var x = Guid.Empty; 
Contract.Invariant(
    this.isSubsidiary || 
    this.parentCompanyId == x); 

Ich denke, sie tatsächlich die checker modifizierte einige Zuweisungen wie dies zu ermöglichen (für einfache Bedienung), aber dass sie nicht alle Fälle erlaubt ... ob dies beabsichtigt ist oder nicht, ist jenseits meines Wissens.

Ich würde dies auf der melden, kann es ein Fehler sein.