Скажем, у меня есть набор типов формы BooleanAttribute
, ContinuousAttribute
, FiveStarAttribute
и т. д. Каждый из них концептуально связан с типом значения (например, bool
, double
, int
для примеров выше.) Каждый также наследует от общего базового класса AttributeBase
,
Скажем, у меня есть еще один общий класс под названием AttributeUpgrade<Attr>
который содержит в качестве члена экземпляр Attr
, где Attr
наследуется от AttributeBase
, Я также хотел бы, чтобы он содержал два экземпляра (старый и новый) типа значения, концептуально связанного с Attr
,
С шаблонами C ++ это было бы тривиально. В каждом типе в наборе атрибутов я определяю typedef для ValueType и объявляю своих членов как
template <typename Attr>
class AttributeUpgrade
{
Attr attribute;
typename Attr::ValueType old;
typename Attr::ValueType new;
...
До сих пор эквивалентное решение в C #, или что-нибудь рядом с ним, намекало на меня. Любые решения приветствуются, даже если они предполагают разрыв части структуры в примере. В моем нынешнем виде я стремлюсь отказаться от безопасности типов и просто набирать старые и новые как объекты. Спасибо!
Попробуй это:
class AttributeUpgrade<T> where T : Attr
{
T oldOne;
T newOne;
}
И помните, что new
является зарезервированным ключевым словом.
Предложение where является необязательным, но вы можете ограничить используемые типы Attr
Редактировать: Я упустил спецификаторы доступа для класса и членов для ясности, поскольку я не знаю, какой уровень доступа необходим.
Редактировать: Ответ из комментариев:
В моих словах: вы хотите повторно использовать параметр шаблона из Attr в объявлении AttributeUpgrade, не вводя новый универсальный параметр в AttributeUpdate.
Это не может быть сделано в C #.
Вам либо понадобится второй параметр шаблона, либо прибегните к использованию GetType()
на внутренний тип Attr, чтобы получить System.Type
(но, как вы знаете об этом, здесь нет безопасности типов).
C ++ решает эту проблему, используя typedef в классах. Наиболее близкими здесь являются псевдонимы, но они не могут предоставить нужную вам функцию.
См. Stackoverflow.com/questions/19790556/c-sharp-typedef-generics.
На самом деле, я думаю, что «лучшим» способом здесь было бы добавить еще один параметр шаблона, и во время выполнения (!) Утверждать, что внутренний тип Attr равен тому, что в AttributeUpgrade
,
Похоже, вы пытаетесь писать шаблоны C ++ с использованием обобщений C #. Однако они немного отличаются как по концепции, так и по исполнению. Что вы на самом деле пытаетесь создать? Какую оригинальную проблему вы решаете?
Если я понимаю ваше намерение, простое решение состоит в том, чтобы сам AttributeBase был универсальным.
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;
}
Если вы не можете позволить себе использовать базовый базовый класс, вы можете использовать интерфейсы для переопределения некоторых вещей по мере необходимости (т. Е. Либо иметь универсальный шаблон и неуниверсальный класс, либо наоборот), но я ожидаю, что это не так , поскольку у вас будет такая же проблема с шаблонами C ++.
В отличие от шаблонов, дженерики C # разрешаются по требованию во время выполнения, они не являются просто этапом предварительной обработки во время компиляции. Это, конечно, имеет свои плюсы и минусы, и они совсем не одно и то же. Это не означает, что вы не можете использовать универсальные шаблоны для решения проблемы, которую вы решили с помощью шаблонов в C ++, — это не просто синтаксический сахар, как в C ++. Вы можете использовать генераторы кода, чтобы сделать что-то, как делают шаблоны C ++, но это выходит за рамки SO вопроса: D