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
{
}
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've been trying to do something which I hoped would be simple, but turned otherwise.
I have a base class:
public class EntityBase
{
}
and two classes that inherit from it:
public class EntityA : EntityBase
{
}
public class EntityB : EntityBase
{
}
I want to use a container type that will wrap
An instance of EntityBase
A number of children which are other instances of the container type.
I want this container expose the exact type of the EntityBase instance it contains, so I use C# generics. But I could not manage to convince C# compiler to define a list of the container type (which has a type parameter now):
public class EntityNode<T> where T : EntityBase
{
private T _node;
private List<EntityNode<EntityBase>> _children = new List<EntityNode<EntityBase>>();
public EntityNode(T pNode)
{
_node = pNode;
}
public void AddChild(EntityNode<T> pNode)
{
//_children.Add(pNode); //this is not going to work...
}
public T Root
{
get { return _node; }
set { _node = value; }
}
}
Is it possible to allow EntityNode to contain a list which in turn contains EntityNode<EntityA>, EntityNode<EntityB> and EntityNode<EntityBase> instances?
What about using List<EntityNode<T>> instead of List<EntityNode<EntityBase>>:
private List<EntityNode<T>> _children = new List<EntityNode<T>>();
I'm looking for a way to create a generic base class that has a typesafe taxonomy using internal properties.
Just to be clear, the class doesn't have to use the generics language feature as long as it is generic itself and I'm looking for something that has compile-time type safety.
As an example here is a simple taxonomy I want to represent using multiple instances of the same class
Wood
Crate
Box
Metal
Crate
Bar
The permutations of which are
Wood Crate
Wood Box
Metal Crate
Metal Bar
initially I though I could use enums to represent the different levels of taxonomy like so
public enum EFirstLevel
{
Wood,
Metal
}
public enum ESecondLevel
{
Crate,
Box,
Bar
}
public class BaseItem
{
EFirstLevel FirstLevel;
ESecondLevel SecondLevel;
public BaseItem(EFirstLevel aFirst, ESecondLevel aSecond)
{
FirstLevel = aFirst;
SecondLevel = aSecond;
}
}
I could create the items above using:
var item1 = new BaseItem(EFirstLevel.Wood,ESecondLevel.Crate)
var item2 = new BaseItem(EFirstLevel.Wood,ESecondLevel.Box)
var item3 = new BaseItem(EFirstLevel.Metal,ESecondLevel.Crate)
var item4 = new BaseItem(EFirstLevel.Metal,ESecondLevel.Bar)
but I could also create
var item5 = new BaseItem(EFirstLevel.Wood,ESecondLevel.Bar)
which for my purposes is incorrect.
Do any of you know of a pattern that would let me create a single class to represent the example taxonomy in a type-safe way that prohibits the creation of incorrect combinations.
It also needs to be applicable to N levels of taxonomy, the 2 levels above are just an example.
Thank you
Update:
I do require compile-time type safety.
I could do this with multiple classes quite easily using inheritance and such, I'm trying to find a solution using instances of just a single base class.
let me know if you need any more info
Update:
#Maarten Yes, i'm trying to sure that the hierarchy is maintained so if EFirstLevel is 1 then ESecondLevel must be either Crate or Box.
Just to clairify i'm happy to have other supporting classes, what i'm trying to avoid is having to explicitly create a class for each taxanomic value.
What I'm trying to accomplish is providing an example layout of class that that maintains this taxanomic type safety so I can reflect over it and permute combinations. While maintaining the type safety should I need to generically instantiate said permutations.
The class upon which I might reflect could come form a third party and as such I might not know beforehand the values for each level.
I could generate all the possible combinations into a set of classes with type safe internal enums but this would require regeneration of said classes any time you changed the items in any level.
I was just wondering if there was a was to achieve my goals without having to generate any classes.
EDIT: Moved this section to an answer
I don't think you're going to be able to get away without creating classes/interfaces and having compile-time checks that that objects conform to your taxonomy.
I'd suggest a solution as follows:
// Define the taxonomic levels here. Each level (except the first) references its next-higher taxonomic level in a type constraint
interface Material { }
interface Object<TMaterial> where TMaterial : Material { }
// Define the items in the highest taxonomic level (materials)
interface Wood : Material { }
interface Metal : Material { }
// Define the items in the 2nd taxonomic level (objects), implementing the appropriate interfaces to specify what the valid top-level taxonomies it can fall under.
interface Crate : Object<Wood>, Object<Metal> { }
interface Bar : Object<Metal> { }
interface Box : Object<Wood> { }
// Define an item class with type constraints to ensure the taxonomy is correct
abstract class Item<TMaterial, TObject>
where TMaterial : Material
where TObject : Object<TMaterial>
{
}
With the above defined, we can now define valid items:
class MetalBar : Item<Metal, Bar> { }
class MetalCrate : Item<Metal, Crate> { }
class WoodCrate : Item<Wood, Crate> { }
class WoodBox : Item<Wood, Box> { }
However attempting to create an invalid item (e.g. a wooden bar) results in a compile time error:
class WoodBar : Item<Wood, Bar> { }
The type 'Taxonomy.Bar' cannot be used as type parameter 'TObject' in the generic type or method 'Taxonomy.Item'. There is no implicit reference conversion from 'Taxonomy.Bar' to 'Taxonomy.Object'
Two ways -
Create an enum which will contain the leaves of your tree, in your case Wood_Crate, Wood_box and so on. Easy to do and less easy to maintain or read.
Define a class called Category and a static class for each of the elements in your tree. For example
public class Category
{
internal Category() {};
public string Id; // This would be used to understand what you got, can be a list of enums or something
}
public static Category CrateCategory = new Category {Id = "Wood.Crate"};
public static class Wood
{
// either way will work, one will let you directly access CrateCategory (if that is what you wish), the second will remove the need for different Crate categories
public static Category Crate { get { return CrateCategory; } }
public static Category Box { get { return new Category { Id = "Wood.Box" }; } }
}
Your BaseItem constructor will only receive a Category. And could write something like
new BaseItem(Box.Crate);
If you place the Category class in another assembly, you will sure no one would be able to create their own Categories.
That's a bit more work, but seems more elegant and readable to me. If N is extremely large, you could write some code to generate the classes and Category identifiers for you.
My suggestion would be to create a class for each type and then let the valid subtype inherit from this type.
Finally edit the BaseItem type to be generic and only accept valid types.
Like this (Sorry bad at explaining)
class Wood {}
class Metal {}
class Crate : Wood, Metal {}
class Box : Wood {}
class Bar : Metal {}
class BaseItem<T1, T2> where T2 : T1
{
}
This will give you compile time type safety (but I don't think it's the best way)
Think I've found what I'm looking for
#Iridium had an answer close to what I think is going to be my solution, however rather than having to define each item as a class I think I've found a way to maintain the type safety and still be able to create the items as properties of a single base class.
As in #Iridium's answer it does require the creation of linked classes defining the taxonomic relationships.
Instead of using interfaces I remembered an SO answer I found a long time ago about pseudo enum inheritance with a protected constructor
Question is Here see the answer by "Seven"
If I define 2 base classes on which I can base the taxonomic chaining classes
public class ChainEnum
{
public int IntValue { get; protected set; }
public static readonly ChainEnum None = new ChainEnum(1);
protected ChainEnum(int internalValue)
{
this.IntValue = internalValue;
}
}
public class ChainLinkEnum<TParent> : ChainEnum where TParent : ChainEnum
{
public TParent Parent { get; protected set; }
protected ChainLinkEnum(int internalValue, TParent aParent)
: base(internalValue)
{
Parent = aParent;
}
}
I can then use these to chain as many levels deep as needed (for very deep trees this may not be ideal)
The first level inherits from the chain enum with no parent
public class HEBaseMaterial : ChainEnum
{
public static readonly HEBaseMaterial Wood = new HEBaseMaterial(1);
public static readonly HEBaseMaterial Metal = new HEBaseMaterial(1);
protected HEBaseMaterial(int internalValue) : base(internalValue) { }
}
Subsequent levels inherit from the chain link enum which defines a parent
public class HEWoodItemTypes : ChainLinkEnum<HEBaseMaterial>
{
private static readonly HEBaseMaterial InternalParent = HEBaseMaterial.Wood;
public static readonly HEWoodItemTypes Box = new HEWoodItemTypes(1);
public static readonly HEWoodItemTypes Crate = new HEWoodItemTypes(1);
protected HEWoodItemTypes(int internalValue) : base(internalValue, InternalParent)
{ }
}
public class HEMetalItemTypes : ChainLinkEnum<HEBaseMaterial>
{
private static readonly HEBaseMaterial InternalParent = HEBaseMaterial.Metal;
public static readonly HEMetalItemTypes Box = new HEMetalItemTypes(1);
public static readonly HEMetalItemTypes Bar = new HEMetalItemTypes(1);
protected HEMetalItemTypes(int internalValue) : base(internalValue, InternalParent) { }
}
A third level would use a signature like
public class HEThirdLevelType : ChainLinkEnum<HEWoodItemTypes>
After that set-up I can then define my single base item class like:
public class TwoLevelItem<T1,T2>
where T1 : ChainEnum
where T2 : ChainLinkEnum<T1>
{
public T1 LevelOne { get; set; }
public T2 LevelTwo { get; set; }
}
or if I wanted an item with 5 levels of taxonomy where each is linked to the one before
public class FiveLevelItem<T1,T2>
where T1 : ChainEnum
where T2 : ChainLinkEnum<T1>
where T3 : ChainLinkEnum<T2>
where T4 : ChainLinkEnum<T3>
where T5 : ChainLinkEnum<T4>
{
public T1 LevelOne { get; set; }
public T2 LevelTwo { get; set; }
public T3 LevelThree { get; set; }
public T4 LevelFour { get; set; }
public T5 LevelFive { get; set; }
}
or 3 properties with one first level and 2 second levels both linked to the first
public class LinkedItem<T1,T2_1,T2_2>
where T1 : ChainEnum
where T2_1 : ChainLinkEnum<T1>
where T2_2 : ChainLinkEnum<T1>
{
public T1 LevelOne { get; set; }
public T2_1 LevelTwoOne { get; set; }
public T2_2 LevelTwoTwo { get; set; }
}
Once the single base class is defined, i can reflect over it and the chain enums to get the permutations.
each item is created as a property
var metalBox = new TwoLevelItem<HEBaseMaterial,HEMetalItemTypes>()
{
LevelOne = HEBaseMaterial.Metal,
LevelTwo = HEMetalItemTypes.Box
}
This maintains the type safety and means that I can new properties to a taxonomy level and not have to create classes for items(although I do have to generate the extra items as properties)
This seems to do all i wanted but i've yet to try it extensively.
#Iridium's answer was close but not quite what I was looking for, although it did help.
in my Silverlight 4 application, I am trying to use generics, but there is another problem, that I hope to solve with the help of the stackoverflow-community:
I have a Tree-Structure, that can have two modes, Editor-mode, where the tree is created, nodes added, moved, deleted etc. and a Configurator-mode, where the user can i.e. select nodes of the tree.
To represent the tree, I created a base class for both modes, and a derived class for each mode. As the Editor-mode can only have Editor-Nodes and the Configurator-Mode can only have Configurator-Nodes, I made the baseclass generic:
public abstract class ServiceModelBase<TRootNodeType>
where TRootNodeType : ServiceNodeVMBase
{
public TRootNodeType RootNode
{
get { return _rootNode; }
}
...
}
public class ServiceModelConfigurator : ServiceModelBase<ServiceNodeVMConfigurator>
public class ServiceModelEditor : ServiceModelBase<ServiceNodeVMEditor>
Both ServiceNodeVMConfigurator and ServiceNodeVMEditor inheriting from ServiceNodeVMBase
The application can save and load the saved data. Loading works (in short) this way:
1.) Deserialize the serialized data in a special Datatransferobject.
2.) Depending on the type of the Datatransferobject, creating a ServiceModelConfigurator or ServiceModelEditor
3.) Firing an event, that contains (beside others) the created ServiceModel
I have created a class derived from EventArgs that have to store the ServiceModel. As this ServiceModel can be Editor or Creator, I declared the Property to store it of the baseclasstype:
public class ServiceModelLoadedEventArgs : EventArgs
{
public ServiceModelBase<ServiceNodeVMBase> ServiceModel;
...
}
But unfortunatly, I cannot assign the derived ServiceModelEditor/Configurator to the EventArgs ServiceModel variable:
ServiceModelLoadedEventArgs args = new ServiceModelLoadedEventArgs();
args.ServiceModel = new ServiceModelEditor();
The compiler tells me, that it cannot convert ServiceModelEditor in ServiceModelBase
Can anyone tell me, how I have to write the code for the EventArgs-class that I can assign a ServiceModelEditor or ServiceModelConfigurator to the ServiceModel variable?
PS: I want to apologize that this is just another generics related question from me, but I fear generics and me are not really friends yet.
To use covariance you'll have to declare a covariant interface:
public interface IServiceModelBase<out TRootNode>
where TRootNode : ServiceNodeVMBase
{
TRootNode RootNode { get; }
}
public abstract class ServiceModelBase<TRootNode> : IServiceModelBase<TRootNode>
{
...
}
public class ServiceModelLoadedEventArgs : EventArgs
{
public IServiceModelBase<ServiceNodeVMBase> ServiceModel { get; set; }
...
}
public class ServiceModelEditor : ServiceModelBase<ServiceNodeVMEditor>
And:
ServiceModelLoadedEventArgs args = new ServiceModelLoadedEventArgs();
args.ServiceModel = new ServiceModelEditor();
You can use co-variance:
public abstract class ServiceModelBase<out RootNodeType>
where RootNodeType : ServiceNodeVMBase
{
}
Consider the following scenario.
Document -> Section -> Body -> Items
Document has sections, a section contains a body. A body has some text and a list of items. The items is what the question is about. Sometimes the items is a basic list of string, but sometimes the items contain a list of a custom datatype.
So:
public class Document
{
public Section[] Sections{get;set;}
}
public class Section
{
public SectionType Type{get;set;}
public Body {get;set;}
}
public class Body
{
//I want the items to be depending on the section type.
//If e.g. the sectiontype is experience, I want the Items to be created with type //Experience. If sectiontype is default I want the Items to be created with type string
public Items<T> Items {get;set;}
}
public class Items<T>:IEnumerable, IEnumerator
{
// Do all the plumbing for creating an enumerable collection
}
public class Experience
{
public string Prop1{get;set;}
public string Prop2 {get;set;}
}
I can´t get this to work. The property Items has to be defined by a type in order to compile. I am stuck here. I can fix this easily by creating a Section class for each of the kind of sections I use. But the thing is that all the other code is the same and all the operations on the section will be the same. The only thing different is the type of list used in the Body.
What is the best practice for this. I have tried generics, abstraction etc. I can make it work if creating the Items class directly from the calling program, but I can´t get it to work if Items is declared a property on another class.
I can provide more details if needed. Thank you guys and girls for your support.
This class isn't valid:
public class Body
{
public Items<T> Items {get;set;}
}
You need to define a concrete type here OR make Body a generic type also. So either:
public class Body<T>
{
public Items<T> Items {get;set;}
}
or:
public class Body
{
public Items<MyClass> Items {get;set;}
}
Make an interface for Items
public interface IItems: IEnumerable, IEnumerator{
}
public class Items<T>: IItems
{
// Do all the plumbing for creating an enumerable collection
}
Then use that everywhere else.
public class Body
{
//I want the items to be depending on the section type.
//If e.g. the sectiontype is experience, I want the Items to be created with type //Experience. If sectiontype is default I want the Items to be created with type string
public IItems Items {get;set;}
}
The most obvious option is declare your list of type object, but then you have to deal with the performance hit of boxing and unboxing of the object. I think I would create an interface that defines the behavior you are looking for from the item and make sure each item implements that interface.
public IMyInterface
{
string dosomething();
}
public Items<IMyInterface> Items {get;set;}
Then you could ask each item to do something useful as you are iterating through them.
This could work for you:
public class Document<T> where T: IEnumerable, IEnumerator
{
private Section<T>[] Sections{get;set;}
}
private class Section<T>
{
private Body<T> body {get;set;}
}
private class Body<T>
{
private Items<T> Items {get;set;}
}
private class Items<T>:IEnumerable, IEnumerator
{
// Do all the plumbing for creating an enumerable collection
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
/* Needed since Implementing IEnumerator*/
public bool MoveNext()
{
return false;
}
public void Reset()
{
}
public object Current
{
get{ return new object();}
}
}