C# 为什么是";这";委托中的指针为空?

C# 为什么是";这";委托中的指针为空?,c#,.net,C#,.net,我有以下代码(为了清晰起见,删除了详细信息): 私有抽象类基类{ 私有只读系统。Func Func=null; 受保护的基(System.Func Func){ this.func=func; } 公共TResult Execute(){ 返回此.func(); } } 派生的私有类:基{ 公共派生(bool myValue):基(委托(){返回this.myValue();}){ this.myValue=myValue; } private bool myValue=false; 私有boo

我有以下代码(为了清晰起见,删除了详细信息):

私有抽象类基类{
私有只读系统。Func Func=null;
受保护的基(System.Func Func){
this.func=func;
}
公共TResult Execute(){
返回此.func();
}
}
派生的私有类:基{
公共派生(bool myValue):基(委托(){返回this.myValue();}){
this.myValue=myValue;
}
private bool myValue=false;
私有bool MyValue(){
返回this.myValue;//此处的“this”指针为空。。。
}
}
衍生d=新衍生(真);
bool result=d.Execute();//这将导致空引用指针(如上所述)
有什么想法吗

谢谢,戴夫,这合法吗<代码>此时未定义此。IIRC,这是一个编译器错误-已经在4.0中修复

它位于4.0编译器中:

错误1关键字“this”在当前上下文C:\Users\Marc\AppData\Local\Temporary Projects\ConsoleApplication1\Program.cs 22 40 ConsoleApplication1中不可用

引用7.5.7:

A仅允许在实例构造函数、实例方法或实例访问器的块中进行此访问。它具有以下含义之一:

(emph矿)

在除上面列出的上下文以外的上下文中的主表达式中使用此选项是编译时错误。特别是,不可能在静态方法、静态属性访问器或字段声明的变量初始值设定项中引用它


在给出的示例中,它是无效的。

在构造函数中使用
总是很危险的(除非在调用同级构造函数的特殊情况下)。您的
派生的
构造函数在调用时捕获
,该构造函数为空,因为实例尚未构造

通过查看您的代码,我会说这是一个设计问题

为什么不将
Execute
函数抽象化,让派生类提供它们想要的任何实现呢

例如:

private abstract class Base<TResult> {
    public abstract TResult Execute();
}

private class Derived : Base<bool> {
    //...

    public override bool Execute(){
         return this.myValue;
    }

    //....
}

Derived d = new Derived(true);
bool result = d.Execute(); //This should work now
私有抽象类基类{
公共抽象TResult Execute();
}
派生的私有类:基{
//...
公共重写bool Execute(){
返回this.myValue;
}
//....
}
衍生d=新衍生(真);
bool result=d.Execute()//现在应该可以了

这是编译器错误,非常奇怪。让我解释一下细节。如果一些专家能澄清这一点,我会非常高兴

是的,在ctor中捕获
是不正确的,但由于
是在匿名委托中使用的,因此情况变得很热。通常,若匿名委托并没有闭包(并没有捕获外部变量),它将由编译器作为同一类的静态方法实现。事情发生在这里。但是让我们看一下IL代码生成的静态方法:

.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 
}
现在一切都好了!没有NRE!生成了匿名类,它的字段捕获闭包。在这种情况下,将生成正确的IL:

.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 
}
.method公共隐藏实例bool b__0()cil托管
{
.maxstack 2
.init(
[0]bool CS$1$0000)
L_0000:没有
L_0001:ldarg.0
L_0002:ldfld布尔控制台应用程序15.派生/c_显示类别1::myValue
L_0007:ldarg.0
L\u 0008:ldfld类控制台应用程序15.派生控制台应用程序15.派生/c\u显示类1::4\u此
L_000d:调用实例bool ConsoleApplication15.Derived::MyValue()
L_0012:xor
L_0013:stloc.0
L_0014:br.s L_0016
L_0016:ldloc.0
L_0017:ret
}

方法被调用以阻止此关闭。(但仍然使用
调用实例
,嗯)

为什么要将抽象类定义为私有类?@Mitch-它可以嵌套,在这种情况下完全合法。@Marc gravel:当然,但是嵌套的私有抽象类听起来不是很有用…@Mitch-为什么不?他正在展示一个具体的实现。。。添加一个工厂:工作完成了。@Marc Gravel:可能只有我一个人,但我喜欢保持简单。我的意思是一个人可以用镰刀刮胡子,但我可能不会推荐它!IIRC上次我看到这个,生成的IL是垃圾;这仅仅是一个编译器错误——这是有道理的——在没有Resharper的情况下使用了3.5。Marc,你能看看我的答案吗:除了IL是垃圾之外,我不明白为什么要使用
调用实例
。这是我考虑过的一个有效的替代方法,但选择了更通用的方法。然而,根据对4.0编译器的反馈,看起来我将不得不走这条路。感谢大家的投入!干杯Dave@Dave:我不确定它是否会更通用。。。您可以通过委托实现什么,但不能通过继承实现什么(在您的情况下)?我的实际实现有点复杂,我试图通过使用func和Actions使继承层次结构更平坦。然而,事后看来,我认为我的解决方案比它的价值更复杂。我打算用抽象方法或者通用接口重写它。谢谢你的反馈!它是一只虫子;因此,对理智的所有押注/期望都是错误的-不值得过度分析。。。
public Derived(bool myValue) : base(delegate() { return myValue ^ this.MyValue(); }) {
    this.myValue = myValue;
}
.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 
}