문제

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!

도움이 되었습니까?

해결책

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.

다른 팁

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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top