为什么不能将成员方法传递给基类构造函数?

class Flarg { private readonly Action speak; public Action Speak { get { return speak; } } public Flarg(Action speak) { this.speak = speak; } } class MuteFlarg : Flarg { public MuteFlarg() : base(GiveDumbLook) { } private void GiveDumbLook() { } } 

编译器给出错误“非静态字段,方法或属性’Project.Namespace.Class.GiveDumbLook’需要一个对象。

这似乎与将操作作为参数传递给任何其他方法没有什么不同。 为什么这个无效?

编辑好的答案。 谢谢大家。 我想这只会让我感到困惑,因为看起来它似乎是这个问题的另一面硬币; 最高投票答案明确指出

在第一个构造函数运行之前,AC#对象已完全构造并初始化为零。

通过该声明,似乎上述代码应该起作用。 显然有一个微妙的区别。

像这样改写:

 public MuteFlarg() : base(this.GiveDumbLook) { } 

现在很清楚为什么你不能。 在基类构造函数调用中引用它是不合法的。 这不合法,因为它很容易导致错误。 派生类的构造函数尚未运行,因此字段未设置为其初始状态(初始状态由构造函数完成运行时的对象状态定义)。

这在规范的§10.11.1中明确说明:

实例构造函数初始值设定项无法访问正在创建的实例。 因此,在构造函数初始值设定项的参数表达式中引用它是一个编译时错误,因为参数表达式通过简单名称引用任何实例成员的编译时错误。

最后一条语句明确禁止通过简单名称GiveDumbLook

我只是想确保这里有一个微妙的观点。

正如Jason正确指出的那样,在构造函数运行之前,在C#中访问“this”或“this”的任何成员(无论是隐式还是显式)都是不合法的。 所有字段初始值设定项(甚至是基类上的字段初始值设定项)都在任何构造函数体之前运行,因此在任何字段初始值设定项中使用“this”是不合法的。 类似地,“base()”或“this()”构造函数初始化子句在构造函数体之前运行,因此在构造函数初始值设定项的参数中访问“this”或“this”的成员是不合法的。

我们有这种行为的原因是因为在正文运行之前访问“this”是一个糟糕的编程习惯。 很可能导致在字段初始化中存在排序依赖性。 很可能导致意外地观察到“只读”字段处于未初始化状态。 很可能导致虚拟方法调用更多派生方法,这些方法依赖于尚未初始化的状态才能正确运行。 所有这些都会产生错误,C#应该是一种可以防止设计错误的语言。 基本上,我们不希望您触摸“this”,直到您在方法体中并且可以执行更高级的逻辑而不仅仅是分配到字段。

事实并非如此,因为“尚未创建基础对象”或某些此类事物,因此无法访问“this”。 在构造函数或字段初始值设定项的任何部分开始运行之前,保证对象完全创建并初始化为其默认状态。 “this”对象肯定存在于字段初始化程序正在运行的位置 – 它必须存在,因为字段初始化程序正在修改它!

简而言之:我们不会让你触及“这个”,因为这样做很容易出错,不是因为这样做是不可能的。

在这种特定情况下,您将一个委托的委托传递给基础构造函数,该构造函数可以调用该委托,从而调用可能依赖于尚未创建的状态的方法,因为更多派生的构造函数体尚未运行。

只能将静态字段传递给基础构造函数。 该对象尚未初始化,因此您无法使用实例成员。 如果你使GiveDumbLook静态,它将起作用。

请记住,委托由两部分组成:

  • 一种调用的方法
  • 目标实例

在调用基础构造函数时,该方法是已知的,但目标实例尚未构造。

因此,您可以省略目标实例,创建一个开放的委托。 最简单的方法是使用lambda:

 class Flarg { private readonly Action speak; public Action Speak { get { return this.speak; } } public Flarg(Action speak) { this.speak = () => speak(this); } } class MuteFlarg : Flarg { public MuteFlarg() : base(x => ((MuteFlarg)x).GiveDumbLook()) { } private void GiveDumbLook() { } } 

因为在基类( Flarg )构造的阶段,您没有MuteFlarg类的实例,因此无法访问非静态方法或字段。

当对象尚未构建时,如何传递非静态成员?

在创建基础对象时,该对象尚不存在。 那么它应该如何制作方法的“指针”呢?