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.