Understanding C# field initialization requirements

前端 未结 4 1898
一生所求
一生所求 2020-12-06 09:15

Considering the following code:

public class Progressor
{
    private IProgress progress = new Progress(OnProgress);

    private void          


        
4条回答
  •  离开以前
    2020-12-06 09:37

    Everything in my answer is just my thoughts on 'why it would be dangerous to allow that kind of access'. I don't know if that's the real reason why it was restricted.

    C# spec says, that field initialization happens in the order fields are declared in the class:

    10.5.5.2. Instance field initialization

    The variable initializers are executed in the textual order in which they appear in the class declaration.

    Now, let's say the code you've mentioned is possible - you can call instance method from field initialization. It would make following code possible:

    public class Progressor
    {
        private string _first = "something";
        private string _second = GetMyString();
    
        private string GetMyString()
        {
            return "this is really important string";
        }
    }
    

    So far so good. But let's abuse that power a little bit:

    public class Progressor
    {
        private string _first = "something";
        private string _second = GetMyString();
        private string _third = "hey!";
    
        private string GetMyString()
        {
            _third = "not hey!";
            return "this is really important string";
        }
    }
    

    So, _second get's initialized before _third. GetMyString runs, _third get's "not hey!" value assigned, but later on it's own field initialization runs, and it's being set to `"hey!". Not really useful nor readable, right?

    You could also use _third within GetMyString method:

    public class Progressor
    {
        private string _first = "something";
        private string _second = GetMyString();
        private string _third = "hey!";
    
        private string GetMyString()
        {
            return _third.Substring(0, 1);
        }
    }
    

    What would you expect to be value of _second? Well, before field initialization runs all the fields get default values. For string it would be null, so you'll get unexpected NullReferenceException.

    So imo, designers decided it's just easier to prevent people from making that kind of mistakes at all.

    You could say, OK let's disallow accessing properties and calling methods, but let's allow using fields that were declared above the one you want to access it from. Something like:

    public class Progressor
    {
        private string _first = "something";
        private string _second = _first.ToUpperInvariant();
    }
    

    but not

    public class Progressor
    {
        private string _first = "something";
        private string _second = _third.ToUpperInvariant();
        private string _third = "another";
    }
    

    That's seems useful and safe. But there is still a way to abuse it!

    public class Progressor
    {
        private Lazy _first = new Lazy(GetMyString);
        private string _second = _first.Value;
    
        private string GetMyString()
        {
            // pick one from above examples
        }
    }
    

    And all the problems with methods happen to come back again.

提交回复
热议问题