I have an abstract class BaseItem declared like this:
public abstract class BaseItem
{
public BaseItem Parent { get; protected set; }
public List<BaseItem> Children = new List<BaseItem>();
public abstract string Function1();
}
Basically, i'm trying to implement a design where each Item has a parent that will be of one specific type and children that will be of a different type.
For example, ItemA would have children all of ItemB type. Then ItemB would have a parent of ItemA type and children all of ItemC type. ItemC would have parent of ItemB and children of ItemD type.
I thought it would be neater to do this using generics to avoid unnecessary casts since i know what type the parent and children will be for each of my inherited classes. So i came up with something like this:
public abstract class AbstractBase
{
public abstract string Function1();
}
public abstract class BaseItem<T1, T2> : AbstractBase
where T1 : AbstractBase
where T2 : AbstractBase
{
public T1 Parent { get; protected set; }
public List<T2> Children = new List<T2>();
}
public class ItemA : BaseItem<ItemA, ItemB>
{
}
public class ItemB : BaseItem<ItemA, ItemC>
{
}
public class ItemC : BaseItem<ItemB, ItemD>
{
}
public class ItemD : BaseItem<ItemC, ItemD>
{
}
So two things.
1. Is this a good design? Is there a simpler/better way of doing this? I don't really like using a second abstract base class just to be able to use generics.
2. If i do keep this, what's the best way of handling the ends? (i.e ItemA does not have a parent in my actual problem domain, but it needs a parent to compile. ItemD does not have children, but i need to give it something)
If I understand you right, you are saying that ItemA never has a parent and ItemD never has any children, right? To be honest, I would probably just declare the separate classes with their own parent/children properties of the right type:
public abstract class AbstractBase
{
public abstract string Function1();
}
public class ItemA : AbstractBase
{
public List<ItemB> Children = new List<ItemB>();
}
public class ItemB : AbstractBase
{
public ItemA Parent { get; protected set; }
public List<ItemC> Children = new List<ItemC>();
}
public class ItemC : AbstractBase
{
public ItemB Parent { get; protected set; }
public List<ItemD> Children = new List<ItemD>();
}
public class ItemD : AbstractBase
{
public ItemC Parent { get; protected set; }
}
The only thing you are repeating here is the Parent and Children property/field. All the other common functionality you can implement in the AbstractBase. (Unless, of course, that functionality needs access to the parents/children — but then you’re back to square one even in your solution.)
I would do it like this:
public interface IChildOf<T> {
T Parent { get; set; }
}
public interface IParent<T> {
List<T> Children { get; set; }
}
//This class handles all of the cases that have both parent and children
public abstract class BaseItem<T1, T2> : IParent<T1>, IChildOf<T2>
{
public List<T1> Children { get; set; }
public T2 Parent { get; set; }
}
//This class handles the top level parent
public class ItemA : IParent<ItemB>
{
public List<ItemB> Children { get; set; }
}
public class ItemB : BaseItem<ItemC, ItemA>
{
}
public class ItemC : BaseItem<ItemD, ItemB>
{
}
//.... as many intermediates as you like.
//This class handles the bottom level items with no children
public class ItemD : IChildOf<ItemC>
{
public ItemC Parent { get; set; }
}
You might use two generic interfaces, ChildOf<T> and IList<T>. This will let you handle the end cases. Unfortunately since .NET doesn't have multiple inheritance, you won't be able to share the implementation.
Alternatively you could use the abstract class and a marker type (System.Void would be ideal, but I don't think it would compile) for the end cases, and check for it from the Parent/Children properties and throw an exception.
It doesn't seem like too bad an idea, although to be honest I'd be tempted to keep the original solution and put up with the casting as it does add a fair bit of complexity for not that much benefit. (Although I must admit I try to replace casting with generics whenever I can).
If you did want to keep it, a couple of suggestions:
have AbstractBase as an interface
do something different for the ends (e.g. two extra BaseItems which take a parent and a child generic type).
Obviously, this second point only adds to the complexity, which is another reason I'm not sure it's worthwhile.
I don't see a problem with doing things this way, since you appear to have a specific heirarchy that requires top-level items to be of type ItemA, 2nd-level items to be of type ItemB, etc.
To address the root and leaf nodes, I'd probably define separate classes that also derive from AbstractBase:
public abstract class RootItem<T2> : AbstractBase
where T2 : AbstractBase
{
public List<T2> Children = new List<T2>();
}
public abstract class LeafItem<T1> : AbstractBase
where T1 : AbstractBase
{
public T1 Parent { get; protected set; }
}
public class ItemA : RootItem<ItemB>
{
}
public class ItemB : BaseItem<ItemA, ItemC>
{
}
public class ItemC : BaseItem<ItemB, ItemD>
{
}
public class ItemD : LeafItem<ItemC>
{
}
Related
[Edited for additional clarity]
I have an abstract class where I've defined a property - let's call it 'BulkValueSet'. BulkValueSet is a class which holds a large number of numeric values.
public abstract class Parent
{
public BulkValueSet ValueSet {get;set;}
// additional properties and methods
}
BulkValueSet implements several different interfaces. Let's take two of them called ISpecificValueSetA and ISpecificValueSetB.
public class BulkValueSet : ISpecificValueSetA , ISpecificValueSetB
{
// lots of numbers !
}
Now for the crux of the matter: I have two child classes (ChildA and ChildB) that inherit from the Parent class. I would like for these classes to inherit the BulkValueSet property from the Parent class but modify it via the interfaces defined. I've tried hiding the parent property by using the new keyword
public class ChildA : Parent
{
new public ISpecificValueSetA ValueSet {get;set;}
// additional stuff
}
public class ChildB : Parent
{
new public ISpecificValueSetB ValueSet {get;set;}
// additional stuff
}
the intent being that the property read from the child classes returns the filtered values as provided by the relevant interface. But this isn't really working - Visual studio shows both parent and child properties as being present and accessible and accessing the 'ValueSet' property using the dot operator seems to default to the property defined in the Parent class.
How can I go about this ?
Edit: Adding some additional context - I want to do this with multiple child classes - each with their own interface implementation of BulkValueSet.
what is wrong with it
public abstract class Parent
{
public IBulkValueSet ValueSet {get;set;}
// additional properties and methods
}
update, since the question was changed. Now ISpecificValueSet could be like this
public interface IBulkValueSet : ISpecificValueSetA , ISpecificValueSetB
{
// lots of numbers !
}
public class BulkValueSet : IBulkValueSet
{
// lots of numbers !
}
but it doesn't make much sense to me to inherit a huge class in order to use a part of it.
This is the closest that I think I can get to your desired design:
public interface IParent
{
BulkValueSet ValueSet { get; set; }
}
public abstract class Parent : IParent
{
BulkValueSet IParent.ValueSet { get; set; }
}
public interface ISpecificValueSetA { }
public interface ISpecificValueSetB { }
public interface ISpecificValueSetC { }
public class BulkValueSet : ISpecificValueSetA, ISpecificValueSetB, ISpecificValueSetC { }
public class ChildA : Parent
{
public ISpecificValueSetA ValueSet { get => (this as IParent).ValueSet; }
}
public class ChildB : Parent
{
public ISpecificValueSetB ValueSet { get => (this as IParent).ValueSet; }
}
public class ChildC : Parent
{
public ISpecificValueSetC ValueSet { get => (this as IParent).ValueSet; }
}
I have two kinds of base classes:
public class Parent { }
public abstract class Child : Parent
{
string ChildKey { get; set; }
}
Derived from Parent, there are many kids:
public class Kid1 : Parent { public string Name { get; set; } }
public class Kid2 : Parent { public long Number { get; set; } }
...
and also many Children as a special group of Childs with extra properties:
public class Child1 : Child { public string Street { get; set; } }
public class Child2 : Child { public long Account { get; set; }}
Now I have two generic repository classes where the "Special One" acts more specific on the extra properties by using an additional filter:
public class Repository<T> : IRepository<T> where T : Parent
{
public IEnumerable<T> GetAll() { return something; }
}
public class ChildRepository<T> : Repository<T>, IChildrenRepository<T> where T : Child
{
public override IEnumerable<T> GetAll() { return base.GetAll().Where(x => x.ChildKey == "y"); }
}
with the interfaces:
public interface IRepository<T> where T : Parent
{ IEnumerable<T> GetAll(); }
public interface IChildRepository<T> : IRepository<T> where T : Child { }
I also need the type safety of the GetAll()-results.
Now I need a generic method to create the desired repository:
IRepository<T> GetRepository() where T : WhatConstraint
{
if (typeof(Child).IsAssignableFrom(T))
return new ChildRepository<T>(); // return 1
return new Repository<T>(); // return 2
}
What is the correct constraint? return 1 needs Child-Constraint (which is wrong for return 2), saying that Type T cannot be used as type parameter in method since there is no implicit reference conversion from T to Child.
The T : Child-constraint is more precise in ChildRepository (and therefore useful, since I can rely on some properties). If I use the same T : Parent-constraint of the Repository, I have to type-check whether T is derived from Child all the times...
Are there any solutions to this?
Okay, here is a detailed solution (which can be written shorter as well as less readable). Since Repository and ChildRepository have conflicting constraints (which is good for the repositories, but bad for GetRepository-factory), I cannot create the ChildRepository using new-keyword. I have to create this object via CreateInstance.
IRepository<T> GetRepository() where T : Parent
{
if (typeof(Child).IsAssignableFrom(T))
{
Type childType = typeof(T); // which is both, Parent and Child
Type classType = typeof(ChildRepository<>);
Type[] typeParams = { childType };
Type repositoryType = classType.MakeGenericType(typeParams);
return Activator.CreateInstance(resultType) as IRepository<T>;
}
return new Repository<T>();
}
Downside of this solution: More complex code analysis, unclear nullability of result, not really intuitive readable (especially existing constraints). But it works.
I have a following class structure:
interface IA
{
List<IB> Children { get; }
}
interface IB
{
IA Parent { get; }
List<IC> Children { get; }
}
interface IC
{
IB Parent { get; }
List<ID> Children { get; }
}
interface ID
{
IC Parent { get; }
}
Classes implementing those interfaces are closely coupled - we have sets of classes XA : A, XB : B, XC : C, XD : D.
What I would like to achieve is knowing the exact type of the parent and children at compile time.
Generics are the obvious way, but the implementation looks awful to me:
interface IA<TA, TB, TC, TD>
where TA : IA
where TB : IB
where TC : IC
where TD : ID
{
List<TB> Children { get; }
}
interface IB<TA, TB, TC, TD>
where TA : IA
where TB : IB
where TC : IC
where TD : ID
{
TA Parent { get; }
List<TC> Children { get; }
}
interface IC<TA, TB, TC, TD>
where TA : IA
where TB : IB
where TC : IC
where TD : ID
{
TB Parent { get; }
List<TD> Children { get; }
}
interface ID<TA, TB, TC, TD>
where TA : IA
where TB : IB
where TC : IC
where TD : ID
{
TC Parent { get; }
}
At the moment it is implemented by casting in runtime, which I consider incorrect. It's like this:
class XA : IA
{
//...
}
class XB : IB
{
//...
public XA StronglyTypedParent { get { return (XA) this.Parent; } }
}
How should it be done? Is there a better way to achieve this? Maybe there exists a structural pattern for solving such problem? Any suggestions would be most welcome. Thank you.
Edit
It looks that my description of the problem is not clear enough. Let's consider a real-world example:
The IA, IB, IC, ID interfaces correspond to some calculations performed for different periods of time - let's rename them to IYearCalculation, IMonthCalculation, IWeekCalculation, IDayCalculation.
We perform different calculations but all of them have the same structure - like:
class YearCalculationA : IYearCalculation
class MonthCalculationA : IMonthCalculation
class WeekCalculationA : IWeekCalculation
class DayCalculationA : IDayCalculation
And then, by
knowing the exact type of the parent and children at compile time.
I mean, for instance, within the DayCalculationA class, knowing the exact type of the corresponding year calculation (which is YearCalculationA - not just IYearCalculation).
I also need to resolve previous calculation on the same level (example: previous day calculation from DayCalculationA), which is of the same type - but without generics I need to perform a runtime cast.
C# does not support return type variance, so this is a pretty common problem. The way I solve it when I need to is explicitly implementing the interface:
class XA : IA
{
//...
}
class XB : IB
{
private readonly XA parent;
public XA Parent { get { return parent; } }
IA IB.Parent { get { return Parent; } } //XA is implicitly convertible to IA so no ugly castings needed
}
Now any expressión like xB.Parent will be typed XA while expressions like iB.Parent will be typed IA. You get the best of both worlds.
You can do this via reflection:
var sampleClassName = XB.StronglyTypedParent.GetType().FullName;
var newClassInstance = Activator.CreateInstance(Type.GetType(sampleClassName));
But when you are getting to the point of doing this, you need to be asking yourself:
"Is this really the right approach?"
Clever tricks like this make the code less maintainable and harder to understand for new developers
Generics commonly used when some algorithm use abstractions and no need to know every details of entities, if you concrete describe every level you no need to use generics, just write four classes.
Need to know your task more detail to advice, but in case your task is about to traverse your tree or something abstract operations, your structure could be like this:
interface INode<TParentType, TChildType>: IRoot<TChildType>, ILeaf<TParentType>
{
}
interface IRoot<TChildType>
{
List<TChildType> Children { get; }
}
interface ILeaf<TParentType>
{
TParentType Parent { get; }
}
class FirstLevel : IRoot<SecondLevel>
{
public List<SecondLevel> Children { get; set; }
}
class SecondLevel : INode<FirstLevel, ThirdLevel>
{
public List<ThirdLevel> Children { get; set; }
public FirstLevel Parent { get; set; }
}
class ThirdLevel : INode<SecondLevel, FourthLevel>
{
public List<FourthLevel> Children { get; set; }
public SecondLevel Parent { get; set; }
}
class FourthLevel : ILeaf<ThirdLevel>
{
public ThirdLevel Parent { get; set; }
}
Please describe what operations will you do with this structure, how it will be loaded, modified and processed?
using C# I have a class which contains among other meta information the root node of a directed graph. Let's call this the Container-Class. This container can appear in two different modes, Editor-Mode and Configurator-Mode. Depending on the mode, the root-node is of a different type NodeEdit or NodeConfig, both inheriting from the same subclass.
public abstract class NodeBase
{
string Name { get; set; }
...
}
public class NodeEdit : NodeBase ...
public class NodeConfig : NodeBase ...
For the container, I also create a base class and inherit from it:
public abstract class ContainerBase
{
NodeBase Root { get; set; }
...
}
When creating the classes for Editor- and Configuratorcontainer by inheriting from ContainerBase, I want to become the type of the Root - property the specific (inherited from NodeBase) type like:
public class ContainerEditor : ContainerBase
{
NodeEditor Root { get; set; }
...
}
But I cannot change the type of a property defined in ContainerBase. Is there a way to solve this problem? I can use the BaseNode-type, and add an element of NodeEditor like
ContainerEditorInstance.Root = new NodeEditor();
because the type NodeEditor is inherited from type BaseEditor, but in the Container-Editor class, I want to explicitly only allow the type of the Root-property to be NodeEditor.
I could check this in the setter and reject all nodes but those of type NodeEditor, but I'd like to have the property be of the specific type, so I can detect wrong assignments at compile-time.
Thanks in advance,
Frank
Use generics:
public abstract class ContainerBase<T> where T:NodeBase
{
T Root { get; set; }
...
}
public class ContainerEditor : ContainerBase<NodeEditor>
{
...
}
You can redeclare it:
public class ContainerEditor : ContainerBase
{
public NodeEditor Root {
get { return (NodeEditor)base.Root; }
set { base.Root = value; }
}
...
}
You can make the container base generic:
public abstract class ContainerBase<TRoot> where TRoot : NodeBase
{
TRoot Root { get; set; }
...
}
In the derived class you specify the type:
public class ContainerEditor : ContainerBase<NodeEditor>
{
...
}
I suppose a good solution here will be Generics. So you'd write something like this:
public class ContainerEditor<T>:ContainerBase
{
T Root {get;set;}
}
I want to create a hierarchical structure that will closely follow the following structure:
(1) INodeBase - contains a Children property that is a Collection of itself (INodeBase)
(2) INodeFolder - derives from INodeBase.
(3) NodeFolder - implements INodeFolder. The implementation of the Children property should allow it to contain items of both the INodeFolder type and INodeItem type.
(4) INodeItem - derives from INodeBase.
(5) NodeItem - implements INodeItem. The implementation of the Children property should allow it to contain items of the NodeResult type.
(6) INodeResult - derives from INodeBase.
(7) NodeResult - implements INodeResult - I don't need/want a children property in this class, but, I am willing to have an empty collection hang off of the class if the overall hierarchy can be structured properly.
Essentially, I want one base type for node - and the assumption should be that a node can contain other nodes. I am thinking that generics is the way to go - but - the problem is that if I query off of the overall hierarchical collection, or rather, if I filter on it, when I am recursively going through each child's children collection (i.e. flattening my collection), I want to know what is what - i.e., if I am in the Children collection of a folder, I want to know when I hit a FolderNode and when I hit an ItemNode, and then when I recurse through the Children property of an ItemNode, I want to know that I am just dealing with the NodeResult type.
So, what is the best approach for the above?
Chris
I think the below code all follows the rules you wanted, particularly with all node implementing INodeBase and with the bonus that NodeResult doesn't have a Children collection.
Here are the interfaces required:
public interface INodeBase
{
}
public interface INodeContainer : INodeBase
{
}
public interface INodeContainer<C> : INodeContainer
where C : INodeBase
{
IList<C> Children { get; }
}
public interface INodeFolder : INodeContainer<INodeContainer>
{
}
public interface INodeItem : INodeContainer<INodeResult>
{
}
public interface INodeResult : INodeBase
{
}
I have added a couple of INodeContainer interfaces - one non-generic & the other generic.
Here are the class definitions:
public abstract class NodeBase : INodeBase
{
}
public abstract class NodeBase : INodeBase
{
}
public abstract class NodeContainer : NodeBase, INodeContainer
{
}
public abstract class NodeContainer<C> : NodeContainer, INodeContainer<C>
where C : INodeBase
{
public NodeContainer() { this.Children = new List<C>(); }
public IList<C> Children { get; private set; }
}
public class NodeFolder : NodeContainer<INodeContainer>, INodeFolder
{
}
public class NodeItem : NodeContainer<INodeResult>, INodeItem
{
}
public class NodeResult : INodeResult
{
}
Now you can use the code like this:
var nf = new NodeFolder();
nf.Children.Add(new NodeFolder()); // Add `INodeFolder`
var ni = new NodeItem();
nf.Children.Add(ni); // or add `INodeFolder`, but nothing else.
var nr = new NodeResult();
ni.Children.Add(nr); // Only add `INodeResult`.
// nr does not have "Children" collection.
You can restrict INodeContainer<C> on the concrete types rather than the interfaces if you wish. It depends on if you want to reference the objects by interface or by concrete class.
Let me know if this works for you.
Altought, is not the main answer, why don't you design your object hierarchy, directly with classes and objects, instead of interfaces. Later you may turn it into an interface hierarchy.
enum NodeTypes { Unknown, Folder, File };
public abstract class CNodeBase {
protected List<CNodeBase> FItems;
public List<CNodeBase> Items();
public virtual NodeTypes NodeType() {
return NodeTypes.Unknown;
}
}
public class CNodeFolder: CNodeBase {
// ...
public override NodeTypes NodeType() {
return NodeTypes.Folder;
}
}
public class CNodeFile: CNodeBase {
// ...
public override NodeTypes NodeType() {
return NodeTypes.File;
}
}
public class CDemo {
void main () {
// root node is ALWAYS A folder
CNodeFolder RootNode = new CNodeFolder("\\");
CNodeBase AnyNode = null;
AnyNode = new CNodeFolder("c:");
RootNode.Add(AnyNode);
AnyNode = new CNodeFolder("d:");
RootNode.Add(AnyNode);
AnyNode = new CNodeFile("readme.txt");
RootNode.Add(AnyNode);
}
}
Superclasses (both abstract or concrete) work very similar to interfaces, but have the advantage that you can instantiate objects from them, see the code working.
Its seems to me, that you are trying to do something very conceptual. Maybe if you step back a little, going to classes that can be instantiated, you may get a more practical view of your idea.
Interfaces are a very good feature, yet, its difficult to understand, at first. Sometimes, is a good idea to "take one step back, to go five steps forward".
Why do you need to have folders and items implement the same interface?
It seems to me that a simpler structure like this would work better...
public class Folder
{
public List<Folder> Folders { get; }
public List<Item> Items { get; }
}
public class Item
{
public List<Result> Results { get; }
}
public class Result
{
}