Making members in subclasses readonly - c#

Let's say I have the class A with member int number which has a getter and a setter.
Then I make a subclass of A and call it B. Now in the class B I wish to keep the member number, but in this class I want to impose the restriction that number is read-only. How can I do this?

The need for that is usually a hint that your design is not optimal (as it violates the Liskov substitution principle). Therefore, C# does not really support it. However, here are two ways to kind of implement it:
(1) Hide the property in the descendent and provide a new property that replaces the getter of the base class. But this does not really protect the property, since you can just cast to the base class:
class A
{
public int Number { get; set; }
}
class B : A
{
public new int Number
{
get { return base.Number; }
}
}
B b = new B();
// b.Number = 42; // This does not work.
A a = b;
a.Number = 42;
Console.WriteLine(b.Number); // == 42. Oops.
(2) Override the setter with an exception throw. But a wrong usage now causes a runtime error instead of a compiler error which is not nice. Consider adding a bool CanSetNumber property to the base (.NET does something similar with Stream.CanSeek and Seek).
class A
{
public virtual int Number { get; set; }
}
class B : A
{
public override int Number
{
get { return base.Number; }
set { throw new InvalidOperationException("B.Number is readonly!"); }
}
}
B b = new B();
b.Number = 42; // BAM!

I agree with Sebastian's answer. Another option to consider is to use a common interface instead of direct inheritance
public interface IHasNumber
{
int Number { get; }
}
public class A : IHasNumber
{
public int Number { get; set; }
}
public class B : IHasNumber
{
public int Number { get; }
}
If you want to share the values then you must encapsulate A in B.
public class B : IHasNumber
{
public B(A data) { this.Data = data; }
private A Data { get; private set; }
public int Number { get { Data.Number; } }
}
To be used as
{
var A = new A();
A.Number = 100; // ok
var B = new B(A);
B.Number = 200; // error
Console.WriteLine(B.Number); // prints 100
}

Related

Inheritance : How copy an object from master class to child class

In order to make an export, I need to overload an object in order to add a property which will transform a property from master class :
public class A
{
public int MyProperty1 { get; set; };
public int MyProperty2 { get; set; };
/*...*/
public myType MyPropertyN { get; set; };
}
public class B : A
{
public override string MyProperty1
{
get :
{
return A.MyProperty1.ToString();
}
set :
{
a.MyProperty1 = int.parse(value);
}
}
}
The problem is my A objects are already instantiated because the model come from the database.
I'm looking for a solution where I can do something like this :
var List<A> myListOfA = PopulateFromSomewhere();
var List<B> myListOfB = myListOfA.Select(x => new B(x)).ToList();
Where A will be copied in B and after call B in my export. I don't want to copy manually all properties of A in the constructor of B. Some objects have more than 20 properties.
Most of the time changing the return-type from a class is a sign of a bad design. In particular it means that you should favour composition over inheritance.
Having said this what you actuall want is to map one class to another. You can do that yourself, e.g. like this:
class A
{
int MyProperty { get; set; }
}
class B
{
private readonly A a;
public B(A a) { this.a = a; }
}
Now you can easily implement your mapping:
class B
{
public string MyProperty
{
get => this.a.MyProperty.ToString();
set => { this.a.MyProperty = int.Parse(value); } // consider to check the value before conversion
}
}
This is just the basic idea. As your models can become huge and doing this mapping yourself therefor becomes pretty cumbersome, you'd best use some automatic mapper, e.g. AutoMapper for that.

Should a property's value be calculated within a class or left to the caller?

Lets say I have an immutable class with a few properties, some of which can be calculated from with in the class, now, I could let the caller calculate the value of each property, or, I could let the class calculate each the properties itself.
For example, in the class below A must be defined. B & C's values can be calculated from A.
Letting the caller define the properties,
class Z
{
public int A { get; private set; }
public int B { get; private set; }
public int C { get; private set; }
public Z(int a, int b, int c)
{
A = a; // Must always be explicitly defined.
B = b; // Explicit definition is optional.
C = c; // Explicit definition is optional.
}
}
Letting the class define as many properties as possible,
class Z
{
public int A { get; private set; }
public int B { get; private set; }
public int C { get; private set; }
public Z(int a)
{
A = a; // Must always be explicitly defined.
B = // Calculation logic involving A...
C = // More calculation logic involving A...
}
}
So are there any conventions stating when/where to use one method over the other (and why)?
You should go with the second approach. It seems pretty clear in this case that computing these derived values is the responsibility of this class. By requiring the caller of the class to do the computations and provide the data to this class it allows the possibility for the class to end up in an invalid state; when it computes the values itself it is able to ensure that it is never in an invalid state.
I'd say that the best way would be something like this:
class Z
{
public int A { get; private set; }
public int B { get {return a*a;} }
public int C { get {return b*a;} }
public Z(int a)
{
A = a; // Must always be explicitly defined.
}
}
In this case you don't need setters for B and C and you have a getter for them which neatly calculates the value. You also evaluate B and C only when it is needed.
couldnt you do the following:
class Z
{
private int a;
public int A { get;
private set
{
a = value;
B = //calculation
C = //calculation
}
}
public int B { get; private set; }
public int C { get; private set; }
public Z(int a)
{
A = a; // Must always be explicitly defined.
}
}

Generics IAbstract<T> inherits from IAbstract

I am trying to achieve something like this:
interface IAbstract
{
string A { get; }
object B { get; }
}
interface IAbstract<T> : IAbstract
{
T B { get; }
}
class RealThing<T> : IAbstract<T>
{
public string A { get; private set; }
public T B { get; private set; }
}
So I can do something like this:
RealThing<string> rt = new RealThing<string>();
IAbstract ia = rt;
IAbstract<string> ias = rt;
object o = ia.B;
string s = ias.B;
Is this possible?
Very nearly. Three things:
You should use new in IAbstract<T> to indicate that you know you're hiding an existing member:
new T B { get; }
But even without that, you'll still only get a warning.
You need to implement the IAbstract.B within RealThing, which you should almost certainly do using explicit interface implementation, delegating to the strongly-typed member:
object IAbstract.B { get { return B; } }
Within your test code, you need to specify a type argument for RealThing:
RealThing<string> rt = new RealThing<string>();
This is fine, and even a reasonably common pattern for times where you want to be able to get a non-generic form of an interface.
Yes, with little changes
interface IAbstract
{
string A { get; }
object B { get; }
}
interface IAbstract<T> : IAbstract
{
new T B { get; }
}
sealed class RealThing<T> : IAbstract<T>
{
public string A { get; private set; }
public T B { get; private set; }
object IAbstract.B
{
get { return B; }
}
}
so you can write
var rt = new RealThing<string>();
IAbstract ia = rt;
IAbstract<string> ias = rt;
object o = ia.B;
string s = ias.B;
Actually the System.Collections.IEnumerator and System.Collections.IEnumerator<T> interfaces do that. When you implement IEnumerable<T>, you will have to implement one of the Current properties explicitly, usually you will pick the non-generic one for that:
object IEnumerable.Current
{
// this calls the implicitly implemented generic property
get { return this.Current; }
}
public T Current
{
get { return this.current; } // or however you want to do it
}
In this case you don't even need two interfaces. Just mark the interface as covariant (supported since C# 4):
interface IAbstract<out T>
{
string A { get; }
T B { get; }
}
and use IAbstract<object> wherever you used the non generic interface before.

Abstract fields in C# - adding set in a child class

I am running into an issue with field inheritance. First I will explain how I would like it to work, and then ask for suggestions on how I can change the syntax to do what I want.
Here's what I tried:
public abstract class A
{
public abstract D D1
{
get;
}
protected D _d2;
public virtual D D2
{
get { return _d2; }
set { _d2 = value; }
}
}
public abstract class B : A
{
protected D _d1;
public override D D1
{
get { return _d1; }
set
{
_d1 = value;
Update();
}
}
}
public abstract class C : A
{
public override D D1
{
get
{
return _d2.Find1();
}
}
public override D D2
{
get { return base.D2; }
set
{
base.D2 = value;
Update();
}
}
}
The problem is that A doesn't compile because it can't find an method to override with D1's set. This how I expected it to work:
A ab = new B();
print(ab.D1);
ab.D1 = 4; // I would expect a compiler error
((B)ab).D1 = 4; // I would expect a compiler error
A ac = new C();
print(ac.D1);
ac.D1 = 4; // I would expect a compiler error
((C)ac).D1 = 4; // **I would expect this to work**
One solution I can see would be to add "set;" to A1's D1 and throw a NotImplementedException if I try to use it in C, but that would prevent the issue from showing up in the compiler. Anyone know of a way around this issue? I would really like to keep them as fields so that I can display them using WPF.
Extending a property with a setter does not work with class inheritance; however, it works with interface implementation
public interface I
{
int Prop { get; }
}
public abstract class A : I
{
public abstract int Prop { get; protected set; }
public abstract int Prop2 { get; }
}
public class B : A
{
public override int Prop
{
get;
set; // ERROR: Cannot change accesibility here.
}
public override Prop2 { get; set; } // ERROR: Cannot add setter here.
}
public class C : I
{
public int Prop { get; set; } // OK: Adding a setter works here.
}
Your error is with class B. In class A you define D1 as public abstract D D1 { get; } However in B you are attempting to override D1 and add a setter -- which is not defined by the abstract class. You'll need to find another way to set the value in B. If other classes need to be able to set D1 then you may want to define D1 as public abstract D D1 { get; set; }
If B only need to be able to set the value, just have it directly set the member value.

Interfaces property name differs from class to class

Here`s the question.
public abstract class A {}
public class B:A
{
public TypeF FieldB;
}
public class C:A
{
public TypeG FieldC;
}
public class TypeF:A { }
public class TypeG:A { }
I want to have interface ex: ITypeFG and to implement it in B and C BUT to have properties names FieldB and FieldC
interface ITypeFG
{
public A FieldFG; //But i want to have names TypeF in A and TypeG in B
}
Can this be done?
Thanks.
explicit interface implementation:
public class B : A, ITypeFG
{
public TypeF FieldB { get; set; } // please don't expose public fields...
A ITypeFG.FieldFG { get { return FieldB; } }
}
public class C : A, ITypeFG
{
public TypeG FieldC { get; set; }
A ITypeFG.FieldFG { get { return FieldC; } }
}
Note that if the interface has a setter, you'll need to cast:
public class B : A, ITypeFG
{
public TypeF FieldB { get; set; }
A ITypeFG.FieldFG { get { return FieldB; } set { FieldB = (TypeF)value; } }
}
public class C : A, ITypeFG
{
public TypeG FieldC { get; set; }
A ITypeFG.FieldFG { get { return FieldC; } set { FieldC = (TypeG)value; } }
}
Two points:
Interfaces in C# can't have fields, but they can have properties.
The desired feature isn't sensible: if clients would always have to know the "specific" name of the implemented interface-property to interact with an implementation, then it isn't much of an interface is it - it's little more than a marker.
As Marc Gravell suggests, a decent workaround is to use explicit implementations. If the client has a reference to the implementing object typed as the interface, they can use the "general" name of the property. If they have a specific reference (i.e. typed as the implementing type) , they can use the "specific" name (and won't be confused by the general name since they won't see it on IntelliSense, for example).
Sounds like you should treat the field names as data along with A. That way you can keep a common interface and only vary the content of what is returned:
class Data
{
public string Name {get;set;}
public A Value {get;set;}
}
interface ITypeFG
{
Data Field {get;}
}
class B : A, ITypeFG
{
public Data Field
{
get
{
return new Data {Name = "TypeF", Value = FieldB};
}
}
}
class C : A, ITypeFG
{
public Data Field
{
get
{
return new Data {Name = "TypeG", Value = FieldC};
}
}
}

Categories

Resources