Question

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!

Was it helpful?

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.

OTHER TIPS

It seems like you're trying to write C++ templates using C# generics. However, they are a bit different in concept as well as in execution. What are you actually trying to create? What's the original problem you're solving?

If I understand your intent, the simple solution is to have AttributeBase itself be generic.

class AttributeBase<T>
{
    T value;
}

class BooleanAttribute: AttributeBase<bool>
{

}

class AttributeUpgrade<T> 
{
    AttributeBase<T> attribute;

    T oldValue;
    T newValue;
}

// Or alternatively...
class AttributeUpgrade<T, K>
    where T : AttributeBase<K>
{
    T attribute;

    K oldValue;
    K newValue;
}

If you can't afford to use a generic base class, you can use interfaces to redefine some things as needed (ie. either have a generic template and a non-generic class or vice versa), but I expect that is not the case, since you would have the same problem with C++ templates.

Unlike templates, C# generics are resolved on demand in runtime, they're not simply a pre-processor step during compilation. This of course has its pros and cons, and they're not the same thing at all. This doesn't mean you can't use generics to solve a problem you solved with templates in C++ - but it's not just syntactic sugar like in C++. You could use code generators to do something like C++ templates do, but that's beyond the scope of an SO question :D

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top