Protected readonly field vs protected property

后端 未结 7 1699
广开言路
广开言路 2021-01-01 17:07

I have an abstract class and I\'d like to initialize a readonly field in its protected constructor. I\'d like this readonly field to be available in derived classes.

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

    Readonly properties were implemented in C# 6.0. This is as simple as:

    protected Foo(int field)
    {
        Field = field;
    }
    
    protected int Field { get; }
    
    0 讨论(0)
  • 2021-01-01 17:20

    Using reflection you can overwrite the readonly field with ease. Using a property makes it harder because the field is hidden ( You can still do it ). So i would prefer a property which is anyway the cleaner because you can change the getter without any issues.

    If you're thinking about performance: Properties are inlined most times.

    Override readonly's

    class Program
    {
        static void Main(string[] args)
        {
            Test t = new Test();
            t.OverrideReadonly("TestField", 5);
            t.OverrideReadonly("TestField2", 6);
            t.OverrideReadonly("TestField3", new Test());
        }
    }
    
    class Test
    {
        protected readonly Int32 TestField = 1;
        protected readonly Int32 TestField2 = 2;
        protected readonly Test TestField3 = null;
    
        public void OverrideReadonly(String fieldName, Object value)
        {
            FieldInfo field = typeof(Test).GetField(fieldName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            field.SetValue(this, value);
        }
    }
    
    0 讨论(0)
  • 2021-01-01 17:22

    I'd leave the implementation or go with:

    protected Field {get; private set;}
    

    (not exactly the same as Field is not readonly for the parent class)

    The advantage of properties over fields is they are more future proof. You can change the implementation on the parent class without affecting the children. Without the property you're committed to the field always being readonly. Using fields is frowned upon for another reason, they hurt opacity: the class describes the exact implementation of the field.

    So yes, leave the encapsulation.

    The only place where I would consider using fields directly for readability is in highly coupled classes such as the states in a state pattern, but in this case the classes themselves would be private.

    0 讨论(0)
  • 2021-01-01 17:24
    abstract class Foo
    {
        protected readonly int _field;
    
        protected Foo(int field)
        {
            _field = field;
        }
    }
    

    Will be appropriate as you want the derived class to be aware of it. Classes not of type Foo won't have access to _field.

    0 讨论(0)
  • 2021-01-01 17:26

    I can think of two reasons to prefer a protected property over a protected field. First, consider this example:

    public class BaseClass 
    {
        protected readonly List<string> _someValues;
    }
    
    public class InheritedClass : BaseClass
    {
        public void NeedsThoseValues()
        {
             DoSomethingWith(_someValues);
        }
    }
    

    Now you decide to change the base class to use lazy instantiation:

    public class BaseClass 
    {
        protected readonly Lazy<List<string>> _someValues;
    }
    

    Now the inherited class(es) must change to call _someValues.Value. Did those inherited classes really need to change? If field was private and exposed to the inherited classes as a property, changing the base class wouldn't break the inherited classes:

    public class BaseClass 
    {
        private readonly Lazy<List<string>> _someValues;
    
        protected List<string> SomeValues => _someValues.Value;
    }
    

    This requires us to change the way we mentally picture inherited classes. We might start off visualizing it like building a larger house around a smaller house. Everything that was in the smaller house is in the larger house, so it's really all one big house. There's no reason to hide the inner house from the outer house.

    In reality it's nothing like that. The base class is its own distinct entity which exists within the larger house. In order to reuse it within multiple houses (multiple inherited classes) we need to encapsulate it so that the inherited classes don't know any more than they need to about it, just like with any other classes they depend on.

    This sometimes creates an odd relationship. We're trying to prevent excessive coupling between the inherited class and implementation details of the base class, and yet they are coupled, because the inherited class can't exist without the base class. That raises the question - why should the inherited class have that relationship with the base class at all? Why not separate what the base class does into its own class, represent it with an abstraction (like an interface) and inject that where it's needed?

    That's the idea behind preferring composition over inheritance. Many, many times inheritance is used to share functionality between classes (the base and the child) when that's not what it's for. If we have two varying areas of functionality, we should accomplish that with two different classes, and one can depend on the other. If we achieve this through inheritance we're going to hit a snag when our class needs to depend on yet another class. We can't give it yet another base class. Unless we're composing distinct classes to work together we might start doing some really evil things like adding more functionality into the existing base classes or creating more levels of inheritance. It gets hard to understand and eventually paints us into a corner.

    The other reason is that when someone sees _someValues referenced in the base class they're going to assume that it's a field declared in the class where it's used since that's the more common convention. It's not going to create any huge confusion but it will take them a moment longer to figure it out.

    These reasons for preferring protected readonly properties over protected readonly fields might not be a problem in many particular cases. But it's hard to know that up front, so it's a good idea to pick the preferred practice and just make a habit out of it while understanding why you're doing it.

    0 讨论(0)
  • 2021-01-01 17:35

    Derived classes are still 'users' of the original code; fields should be encapsulated from them too.

    You should think of base classes as safe and extendable APIs, rather than just classes which expose their internals. Keep the fields private - apart from anything, it allows the base class to change how that property's value is generated :)

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