Search code examples
c#c++genericsmetaprogrammingtype-safety

How can you statically bind types together (as in TypeToType<T>) in C# using generics?


Say I have a suite of types of the form BooleanAttribute, ContinuousAttribute, FiveStarAttribute, etc. Each of these is conceptually bound to a value type (e.g. bool, double, int for the examples above.) Each also inherits from a common base class AttributeBase.

Say I have another generic class called AttributeUpgrade<Attr> that contains as a member an instance of Attr, where Attr inherits from AttributeBase. I would also like it to contain two instances (old and new) of the value type conceptually bound to Attr.

With C++ templates, this would be trivial. In each type in the Attribute suite I would define a typedef for ValueType, and declare my members as

template <typename Attr>
class AttributeUpgrade
{
    Attr attribute;

    typename Attr::ValueType old; 
    typename Attr::ValueType new;
...

So far the equivalent solution in C#, or anything near it, has alluded me. Any solutions would be appreciated, even if they involve tearing apart some of the structure in the example. As it stands, I am headed towards dropping type-safety and just typing old and new as objects. Thank you!


Solution

  • Try this:

    class AttributeUpgrade<T> where T : Attr
    {
        T oldOne; 
        T newOne;
    }
    

    And be aware that new is a reserved keyword.

    The where clause is optional but you might want to restrict the used types to Attr

    Edit: I have omitted access specifiers on class and on members for the sake of clarity as I am not aware of what access level is needed.

    Edit: Answer from comments:

    In my words: You wish to re-use the template parameter from Attr in the declaration of AttributeUpgrade without introducing a new generic parameter to AttributeUpdate.

    This cannot be done in C#.

    You will either need the second template parameter or resort to the use of GetType() on the Attr's inner type to get a System.Type (but as you are aware of this, there is no type safety here). C++ solves this by using typedefs in classes. The closest thing here are aliases but they cannot provide the feature you need.

    See stackoverflow.com/questions/19790556/c-sharp-typedef-generics .

    Indeed I think that the "best" way here would be to add another template parameter and runtime(!) assert that Attr's inner type is equal the one's in AttributeUpgrade.