Why can't a member method be passed to a base class constructor?

后端 未结 7 1690
谎友^
谎友^ 2021-01-07 17:10
class Flarg
{
    private readonly Action speak;

    public Action Speak
    {
        get
        {
            return speak;
        }
    }

    public Flarg(Act         


        
相关标签:
7条回答
  • 2021-01-07 17:30

    Remember that a delegate consists of two parts:

    • a method to call
    • a target instance

    When calling the base constructor, the method is know, but the target instance isn't yet constructed.

    So, you can omit the target instance, creating an open delegate. The easiest way to do this is using a lambda:

    class Flarg
    {
        private readonly Action speak;
    
        public Action Speak
        {
            get
            {
                return this.speak;
            }
        }
    
        public Flarg(Action<Flarg> speak)
        {
            this.speak = () => speak(this);
        }
    }
    
    class MuteFlarg : Flarg
    {
        public MuteFlarg() : base(x => ((MuteFlarg)x).GiveDumbLook())
        {
        }
    
        private void GiveDumbLook()
        {
        }
    }
    
    0 讨论(0)
  • 2021-01-07 17:38

    Rewrite it like this:

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

    and it is now clear why you can't. It's not legal to refer to this in a base class constructor invocation. This is not legal because it can easily lead to bugs. The constructor for the derived class has not run yet, and so the fields are not set to their initial state (initial state being defined by the state of the object when the constructor is done running).

    This is explicitly stated in §10.11.1 of the specification:

    An instance constructor initializer cannot access the instance being created. Therefore it is a compile-time error to reference this in an argument expression of the constructor initializer, as is it a compile-time error for an argument expression to reference any instance member through a simple-name.

    The last statement explicitly forbids referring to this.GiveDumbLook by its simple-name GiveDumbLook.

    0 讨论(0)
  • 2021-01-07 17:40

    I just want to make sure that a subtle point is clear here.

    As Jason correctly notes, it is not legal in C# to access "this" or any member of "this", either implicitly or explicitly, before the constructor body runs. All field initializers (even those on base classes) run before any constructor body, so it is not legal to use "this" in any field initializer. Similarly, the "base()" or "this()" constructor initializer clause runs before a constructor body, and so it is not legal to access "this" or a member of "this" in an argument to the constructor initializer.

    The reason why we have this behaviour is because accessing "this" before the body runs is a bad programming practice. It is highly likely to result in there being ordering dependencies in field initialization. It is highly likely to result in "readonly" fields being accidentally observed to be in their uninitialized state. It is highly likely to result in virtual methods calls to more derived methods that depend on as-yet-uninitialized state to run correctly. All these things make bugs, and C# is supposed to be a language that prevents bugs by design. Basically, we don't want you to touch "this" until you're in a method body and can perform more advanced logic than mere assignment to fields.

    It is not the case that it is impossible to access "this" because "the base object is not created yet" or some such thing. Before any part of the constructor or field initializers begin to run, the object is guaranteed to be fully created and initialized to its default state. The "this" object certainly exists at the point where the field initializers are running -- it has to exist, because the field initializers are modifying it!

    In short: we don't let you touch "this" because doing so is error-prone, not because doing so is impossible.

    In this specific case you're passing a delegate to a method to a base constructor, which could invoke that delegate, thereby invoking a method that might depend on state that has not been created yet, because the more derived constructor body has not run yet.

    0 讨论(0)
  • 2021-01-07 17:40

    the object doesnt exist yet at the moment of the creation of the base object. so how should it already make a "pointer" to the method?

    0 讨论(0)
  • 2021-01-07 17:46

    Only static fields could be passed to the base constructor. The object is not yet initialized so you cannot use instance members. If you make the GiveDumbLook static it will work.

    0 讨论(0)
  • 2021-01-07 17:48

    How can you pass a non static member when the object is not constructed yet?

    0 讨论(0)
提交回复
热议问题