Es ist Compiler-Fehler und sehr seltsam. Lass mich Details erklären. Ich würde mich sehr freuen, wenn einige Experten das klären würden.
Ja, es ist falsch, this
in ctor zu erfassen, aber die Situation wird heiß, weil this
innerhalb anonymer Delegate verwendet wurde. Wenn der anonyme Delegat keine Schließung hat (äußere Variablen werden nicht erfasst), wird er normalerweise vom Compiler als statische Methode derselben Klasse implementiert. Es ist hier passiert.Aber lassen Sie uns einen Blick in den IL-Code werfen, der von dieser statischen Methode generiert wurde:
.method private hidebysig static bool <.ctor>b__0() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
.maxstack 1
.locals init (
[0] bool CS$1$0000)
L_0000: nop
L_0001: ldloc.0
L_0002: call instance bool ConsoleApplication15.Derived::MyValue()
L_0007: stloc.0
L_0008: br.s L_000a
L_000a: ldloc.0
L_000b: ret
}
Haben Sie das gesehen? Sehen Sie sich die Linie L_0002
und die Linie L_0001
genauer an. Es gibt zwei sehr seltsame Dinge:
- Wir haben versucht, Verfahren
MyValue
gegen bool
zu nennen!
- Die Methode wurde als
call
aufgerufen, aber es ist nicht statisch, C# -Compiler ruft normalerweise Instanzmethoden mit callvirt
auf! Wenn der callvirt
verwendet wurde, würde dieser Aufruf fehlschlagen, weil callvirt
auf this == null
überprüft.
Jetzt lasst uns es brechen. Lassen Sie uns Schließung einführen und ändern Sie den Code zu:
public Derived(bool myValue) : base(delegate() { return myValue^this.MyValue(); }) {
this.myValue = myValue;
}
Und jetzt ist alles in Ordnung! Keine NRE! Anonyme Klasse wurde generiert und die Felder erfassen die Schließung. In diesem Fall wird IL korrekt generiert:
.method public hidebysig instance bool <.ctor>b__0() cil managed
{
.maxstack 2
.locals init (
[0] bool CS$1$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: ldfld bool ConsoleApplication15.Derived/<>c__DisplayClass1::myValue
L_0007: ldarg.0
L_0008: ldfld class ConsoleApplication15.Derived ConsoleApplication15.Derived/<>c__DisplayClass1::<>4__this
L_000d: call instance bool ConsoleApplication15.Derived::MyValue()
L_0012: xor
L_0013: stloc.0
L_0014: br.s L_0016
L_0016: ldloc.0
L_0017: ret
}
Methode gegen diese closured genannt wird. (aber immer noch mit call instance
, hmm)
Warum definieren Sie eine abstrakte Klasse als privat? –
@Mitch - es könnte verschachtelt werden, in diesem Fall völlig legal. –
@Marc Gravell: sicher, aber eine verschachtelte private abstrakte Klasse klingt nicht sehr nützlich ... –