Generic class with explicitly type-safe taxonomy

Nat_In_A_Hat

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

Nat_In_A_Hat

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.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

Cast to a type from a generic class

분류에서Dev

Type-safe collection of Type class with defined base type

분류에서Dev

Wordpress Shared Taxonomy (Query specific post type from taxonomy)

분류에서Dev

How do I use an extended generic type's type in a class?

분류에서Dev

Using a bounded generic class to extend another generic class produces an unknown type

분류에서Dev

Spring AOP - using joinpoint to get generic class type (JAVA)

분류에서Dev

How to run method that returns an object of "Type" from generic class

분류에서Dev

Java: Is it possible to compare a Class<?> object with a generic type parameter?

분류에서Dev

How to run method that returns an object of "Type" from generic class

분류에서Dev

Generic type conversion in generic method

분류에서Dev

scalaz join operation requires type explicitly specified

분류에서Dev

Union type for generic param

분류에서Dev

Java Generic type identification

분류에서Dev

generic data type id

분류에서Dev

Issue with generic type bounds

분류에서Dev

FSharp: Type inference with generic

분류에서Dev

Generic Constructor of class

분류에서Dev

Generic class for operations on Number

분류에서Dev

Java Generic Map with Generic Type as key/ values

분류에서Dev

C++: Non generic method in generic class?

분류에서Dev

Generic call signatures and type inference

분류에서Dev

Java generics and casting a generic type

분류에서Dev

Java Generic Type 구문

분류에서Dev

C++ Generic Data Type

분류에서Dev

Lambda: Declare Generic Type Inline

분류에서Dev

Cast object to generic type at runtime

분류에서Dev

Swift generic array with type constraint

분류에서Dev

Java: Getting the generic type of a lambda

분류에서Dev

Resolving generic type with java classmate

Related 관련 기사

뜨겁다태그

보관