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

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.

Related

Get a variable from a class that inherits another

I have an arbitrary amount of classes, classThatInherits, anotherClassThatInherits, etc. that inherit classToBeInherited.
I then have a method, b, that needs to be able to access myValue from the classes that inherit classToBeInherited. How can I achieve this, without casting?
//This class will be inherited by other classes
public class classToBeInherited {
public bool isSomething { get; set; }
}
//This class with inherit 'classToBeInherited'
public class classThatInherits : classToBeInherited {
public int myValue { get; set; } //this needs to be accessable...
}
//...And so will this class
public class anotherClassThatInherits : classToBeInherited {
public int myValue { get; set; }
}
private class normalClass {
private void a() {
classThatInherits cti = new classThatInherits();
b(cti);
anotherClassThatInherits acti = new anotherClassThatInherits();
b(acti);
}
private void b(classToBeInherited c) {
//***
//get myValue from the classes that inherit classToBeInherited
//***
}
}
Move myValue to classToBeInherited:
public class classToBeInherited {
public bool isSomething { get; set; }
public abstract int myValue { get; set; }
}
Then in classThatInherits and anotherClassThatInherits use public override int myValue { get; set; } to implement that property.
Ofcorse, if myValue is needed in only some of the classes, then you can have virtual and not abstract property.
var a = c as anotherClassThatInherits;
if (a != null)
{
var myValue = a.myValue;
}
I don't know why you don't want to do casting, but it's very common to have code like above.
UPDATED
If you really don't want casting, you can use reflection (but you still need to know the type of anotherClassThatInherits)
var getter = typeof(anotherClassThatInherits).GetProperty("myValue").GetGetMethod();
var myValue = getter.Invoke(c, null);

How to design inheritance for multilevel composition classes

I have to solve a quite tricky problem and I will try my best to explain the problem. I have a complicated object and it has two level composition and somehow I am supposed to define two classes for low level of composition and reflect the new types at higher level. In order to reflect the changes in low composition, I am defining two classes in higher levels as well.
I am using abstract factory approach to create instances of higher level classes. All classes are serializable.
C in below diagram is correspond to higher level classes and A is correspond to low level classes. Object of A classes are composed of objects of level 2 classes and they are composed of object of C classes.
In abstract factory approach, I am trying to deserialize the object and return as parent class. I am getting casting related error. However, I think there is some fundamental problem in design which I am unable to figure out. I know parent object can not be casted as child object.
public class A {
public virtual Double [] Prop1 { get; set; }
public virtual Double [] Prop2 { get; set; }
}
public class A1 : A {
public override double[ ] Prop1 {
get {
// implementation other than base class
}
set {
// implementation other than base class
}
}
}
public class A2 : A {
public override double[ ] Prop2 {
get {
// implementation other than base class
}
set {
// implementation other than base class
}
}
}
public class B {
public virtual A A_obj { get; set; }
}
public class B1 : B {
public override A A_obj {
get {
// want to retun the object of A1
}
set {
// want to handle the object A1
}
}
}
public class B2 : B {
public override A A_obj {
get {
// want to retun the object of A2
}
set {
// want to handle the object A2
}
}
}
public class C {
public virtual B [] B_obj { get; set; }
}
public class C1 : C {
public override B[ ] B_obj {
get {
// want to retun the object of B1
}
set {
// want to handle the object B1
}
}
}
public class C2 : C {
public override B[ ] B_obj {
get {
// want to retun the object of B2
}
set {
// want to handle the object B2
}
}
}
Generics may be the way to go here. From my interpretation of your post, the issue seems to be that B1 can only reference A1 objects, B2 -> A2 and similar for C objects.
The following idea will get you type safety and eliminate the necessity to cast:
public abstract class A { };
public class A1 : A { };
public class A2 : A { };
public abstract class B<T> where T : A {
public T A_obj { get; set; }
};
public class B1 : B<A1>
{
};
public class B2 : B<A2>
{
};
public abstract class C<T, U> where T : B<U> where U : A
{
public List<T> B_objs { get; private set; }
public C() {
B_objs = new List<T>();
}
};
public class C1 : C<B1, A1>
{
};
public class C2 : C<B2, A2>
{
};
public static void Test()
{
A1 a1 = new A1();
B1 b1 = new B1();
b1.A_obj = a1;
A2 a2 = new A2();
B2 b2 = new B2();
b2.A_obj = a2;
// The following line fails: cannot implicitly convert A1 to A2
//b2.A_obj = a1;
C1 c1 = new C1();
c1.B_objs.Add(b1);
// The following fails:
// c1.B_objs.Add(b2);
}

Making members in subclasses readonly

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
}

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.

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