Encapsulating correctly the property setter of base class - c#

I'm a bit confused with encapsulation of properties setter in base class.
Supposing some of those properties are set in base constructor, the setter should be private or protected ?
Supposing some of those properties are set in child constructor, the setter should be private or protected ?
In order to be clearer, here is a concrete case :
public abstract class Records
{
public string Date { get; protected set; }
public string Source { get; protected set; }
public string Type { get; protected set; }
public int Value { get; protected set; }
protected Records(string type, string source, int value)
{
Type = type;
Source = source;
Value = value;
Date = DateTime.Now.ToString("hh.mm.ss.ffffff");
}
}
public class NewDocumentRecord : Records
{
public NewDocumentRecord(string source, int value)
: base(ContentTypesString.DocumentNew, source, value)
{
Source = source;
Value = value;
}
}

Generally, it is very hard to make a case for a protected setter in the base class: if a property belongs in the base class, the logic that controls it belongs in the base class as well.
Supposing some of those properties are set in base constructor, the setter should be private or protected?
Assuming that the property is set once in the constructor, and never changes again, the setter should be private, or there should be no setter at all (C# 6 or later).
public string Date { get; }
Supposing some of those properties are set in child constructor, the setter should be private or protected?
If the property is declared in the base class, the task of setting its initial value should be part of base class constructor as well. The best course of action is to pass the value from child constructor to base constructor, letting it validate the data prior to setting the value into the property.
This does not mean that you should never let subclasses modify properties declared in the base class, only that you should avoid making auto-generated setters protected. If you need to make a property modifiable only by subclasses, provide them a protected method to do so.

If you wannna set property only in base class and hide it from children classes you should make setter private.
If you wanna set value only in base ahd children classes you should make it protected.

Related

C# abstract property that can be initialized in constructor but readonly afterwards?

In a class I have a property
protected abstract string test{ get; }
When I try to initialize it in a constructor. I get an error saying:
Property or indexer xxx cannot be assigned to. -- it is read-only.
Is there a way to allow some property to be
abstract
Read-only after initialization in ctor ?
You likely don't want an abstract property. You would only use that if you wanted to force the derived class to provide a custom implementation. In your case you simply want it to be set in the constructor and readonly.
public abstract class Base
{
protected string MyProperty { get; }
public Base(string myProperty)
{
MyProperty = myProperty;
}
}
public class Derived : Base
{
public Derived()
: base("DefaultValue")
{ }
}

Inherited auto-implemented property with private setter

I have a base class and a derived class. Each has the same property which has a private setter so the value can be set by some logic inside the class.
class First
{
internal virtual int Value { get; private set; }
void SetValue(int toValue)
{
Value = toValue;
}
}
class Second : First
{
internal override int Value { get; private set; }
void SetValue(int toValue)
{
Value = toValue;
}
}
This is resulting in a compiler error:
The property or indexer ... cannot be used in this context because the
set accessor is inaccessible.
Why is that the case, and how can I achieve what I'm trying to do? Is this not possible with auto-implemented properties, in other words, do I have to use a backing field instead?
Second would be unable to set the value of Value from First due to Values setter being private. If you need your subclass to be able to set it, it needs to be protected in the base.
Getters and Setters are basically methods. You can't override methods you can't see. The virtual in this case only applies to the getter as virtual private is not allowable.
It's not just that you can't see it to use it, you cannot override it at all.

Why must the accessor be more restrictive than the property?

I have this code:
public string foo { get; set; }
Now, I interpret this as my object has a public property called foo, and both it's accessor's are public. If I write this:
private string foo { get; set; }
I interpret that as my object has a private property called foo, and both it's accessor's are private. I understand making the property itself private. What I don't understand is why the accessor's must be more restrictive? If I write:
private string foo { public get; public set; }
I interpret that my object has a private property called foo, and both's it's accessor's are public, which is the behavior that I want. I'd like the private property with public accessors. I mean, if I have to write a Get/Set method, I will. But I'm just confused as to why this is.
A property is actually (under water) nothing more than two methods:
public string foo { get; set; }
will translate into:
public string get_foo() { ... }
public void set_foo(string value) { ... }
These methods can only have ONE access modifier, not a combination of two.
If I remember correcly, C#v1 did not support access modifiers for the getters and setters. There was one access modifers for the property which was used for both functions.
In v2 it was possible to "override" one of getter/setter-pair, this way overrwriting the "other" function. There was no use to override both getters/setters, because in that would render the property-access modifier useless.
Why the access modifier for the getter/setter is more restrictive has, in my opinion, something to do with easier implementing interfaces which always have (implicitly public) properties.
For more info, read: http://msdn.microsoft.com/en-us/library/75e8y5dd(v=vs.80).aspx
Why you need such a property
private string foo { public get; public set; }
If you want to have you get set public, then make the property public.
The compiler will first check the access of the property and then its method. If the property is public then its method can have either public or private or any accessor

Change Property from a base class to [NonSerialized]

So I have a base class and there a property that is set to be [Serializable].
In the derived class I would like to make that property [NonSerialized].
How can this be done?
This would be a violation of OOP. The base class has established the fact that this property is serializable. It must be possible to substitute any instance of a derived class for an instance of the base class. This means that every instance of the derived class must have that property serializable.
You cannot substitute a new attribute, but you can define a property called ShouldSerializePropertyName (where PropertyName is the name of your property) that always returns false. This should override the presence of the attribute on the property.
For example,
public class BaseClass
{
[Serialized]
public string MyProperty { get; set; }
}
public class ChildClass : BaseClass
{
public bool ShouldSerializeMyProperty { get { return false; } }
}

Adding a setter to a virtual property in C#

I have a situation like this:
public abstract class BaseClass
{
public abstract string MyProp { get; }
}
Now, for some of the derived classes, the properties value is a synthesized values, so there is no setter:
public class Derived1 : BaseClass
{
public override string MyProp { get { return "no backing store"; } }
}
This works fine. However, some of the derived class required a more traditional backing store. But, no matter how I write it, as on automatic property, or with an explicit backing store, I get an error:
public class Derived2 : BaseClass
{
public override string MyProp { get; private set;}
}
public class Derived3 : BaseClass
{
private string myProp;
public override string MyProp
{
get { return myProp;}
private set { myProp = value;}
}
}
Derived2.MyProp.set': cannot override because 'BaseClass.MyProp' does not have an overridable set accessor
How do I get this to work??
The best thing you can do is implement the property as virtual instead of abstract. Make the get and set blocks for each throw NotSupportedException in the base class and override the behaviour accordingly in derived classes:
public virtual string MyProp {
get {
throw new NotSupportedException();
}
set {
throw new NotSupportedException();
}
}
Basically, you cannot. By adding a setter you are changing the definition of the property, so it does not really "override" the base property. It's the same as if you tried to override a method and add another parameter to it - they would be treated as different methods (overloaded). Since properties cannot be overloaded this won't work.
You'll just have to add another method to set the value (perhaps with protected accessibility).
Bradley's suggestion is good, but one thing I've done in cases where only the Setter should be virtual is to do something this this:
public class Root
{
private string _MyProp;
public string MyProp
{
get { return _MyProp;}
set { _MyProp = SetMyProp(value); }
}
protected virtual string SetMyProp(string suggestedValue)
{
return suggestedValue;
}
}
public class Child
: Root
{
protected override string SetMyProp(string suggestedValue)
{
string oReturn = base.SetMyProp(suggestedValue);
// Do some sort of cleanup here?
return oReturn;
}
}
It requires a little extra work up front, but it seems to maintain a higher degree of encapsulation (e.g. you can prevent subclasses from overriding the Getter behavior, and your subclass doesn't have to be aware of the underlying member behind the property).
I would suggest avoiding virtual or abstract properties. Instead, use a non-virtual property which chains to protected virtual or abstract get/set methods. Doing that will allow derived classes to override the methods and also shadow the property with one that has different access modifiers. Since the base property itself will be non-virtual, there will never be any need to override it, so the naming conflict with the new version won't matter.

Categories

Resources