I have a set of business logic classes that inherit from a chain of abstract classes. I also have a set of business data classes that inherit from their own chain of abstract classes. In both cases my derived class (C) inherits from an abstract class (B), which itself inherits from an abstract class (A). (Therefore, C : B and B : A).
In isolation, my chain of logic classes behave as expected. Method calls use the correct base or overridden implementations. The same goes for my data classes (new fields/properties appear at the correct level).
My problem is trying to add the data classes as a property of the logic classes. The base abstract logic class (A) must be able to call upon some fields in the base abstract data class (again, A). However, the next abstract logic class in the chain (B) will need to use some fields/properties in the next level of the chain (B). The same for the derived concrete types (C).
Now, initially I assumed that if in my "A" logic class I add a property for the base abstract data class, I could use this property further up the chain (e.g. in the "B" logic class I could use this.Data.Variable to access the "Variable" field, whereby the "Variable" field is implemented in the "B" data class). I found that without a cast, I was restricted to using the fields exposed in the base abstract data class throughout the entire logic class chain.
I have found some good advice on this site, and went down the path of using generics. I still need to perform a cast in the base logic classes when I use fields on the data class (but do not need to cast when using fields in the derived class).
See below for a sample of my classes. I have implemented a MethodA in the base logic class (LogicA) to demonstrate where I need to cast to the correct data type to use its fields.
abstract class LogicA<T>
{
public T Data { get; set; }
public virtual void MethodA()
{
var data = (DataA)((dynamic)this.Data);
data.FieldA = "T";
}
}
abstract class LogicB<T> : LogicA<T>
{
public virtual void MethodB()
{
}
}
class LogicC : LogicB<DataC>
{
public void MethodC()
{
this.Data.FieldB = "BBB";
}
}
abstract class DataA
{
public string FieldA { get; set; }
}
abstract class DataB : DataA
{
public string FieldB { get; set; }
}
class DataC : DataB
{
public string FieldC { get; set; }
}
When using the logic class, I can perform the following without any issues:
LogicC logic = new LogicC();
logic.Data = new DataC();
logic.Data.FieldA = "A";
logic.Data.FieldB = "B";
logic.Data.FieldC = "C";
logic.MethodA();
Is there a better way to pull off what I am trying to achieve? I can see this approach being tedious with the casting through the abstract logic classes when using the data fields.