Вероятно, это невозможно, но у меня есть такой класс:
public class Metadata<DataType> where DataType : struct
{
private DataType mDataType;
}
Это еще не все, но давайте будем простыми. Универсальный тип (DataType) ограничен типами значений оператором where. Я хочу иметь список этих объектов метаданных разных типов (DataType). Такой как:
List<Metadata> metadataObjects;
metadataObjects.Add(new Metadata<int>());
metadataObjects.Add(new Metadata<bool>());
metadataObjects.Add(new Metadata<double>());
Это вообще возможно?
И абстрактный базовый класс, и интерфейс обеспечивают определенную степень контроля, ограничивая тип элементов, которые могут быть добавлены в список. Я также не могу понять, как в этом проявляется бокс.
Конечно, если вы используете .NET v4.0 или выше, ковариация - это решение. List<Metadata<object>> делает свое дело.
@ 0b101010 Я думал то же самое, но, к сожалению, для типов значений отклонение недопустимо. Поскольку OP имеет ограничение struct, здесь он не работает. Видеть
@ 0b101010, Оба ограничивают только ссылочные типы, любой встроенный тип значения и любую структуру все еще можно добавить. Кроме того, в конце у вас есть список ссылочных типов MetaData вместо ваших исходных типов значений без информации (время компиляции) о базовом типе значения каждого элемента, то есть эффективно «бокс».





public abstract class Metadata
{
}
// extend abstract Metadata class
public class Metadata<DataType> : Metadata where DataType : struct
{
private DataType mDataType;
}
Ух ты! Я действительно не думал, что это возможно! Ты спасатель, чувак!
+10 за это! Не знаю, зачем это компилируется .. Именно то, что мне нужно!
У меня аналогичная проблема, но мой общий класс является наследником другого универсального класса, поэтому я не могу использовать ваше решение ... какие-либо идеи по исправлению этой ситуации?
Есть ли в этом подходе преимущество по сравнению с простым List<object>? пожалуйста, посмотрите мой комментарий, опубликованный под вопросом OP.
@leppie: Можно ли добавить в список несколько экземпляров Metadata?
@SaebAmini Кто-нибудь может ответить на вопрос Саеба? Объект по-прежнему будет упакован как Metadata, как и object. Я пытаюсь понять, почему бы вам просто не использовать List<object>,
@SaebAmini Список <объект> не показывает никаких намерений разработчику и не мешает разработчику выстрелить себе в ногу, ошибочно добавив в список какой-либо объект, не относящийся к метаданным. Используя List <MetaData>, можно понять, что должен содержать список. Скорее всего, у MetaData будут некоторые общедоступные свойства / методы, которые не были показаны в приведенных выше примерах. Доступ к ним через объект потребует громоздкого приведения.
@SaebAmini. С его помощью вы можете помещать «нетипизированные» члены в базовый класс и напрямую обращаться к ним через массив. только члены, связанные с универсальным типом, должны быть в подклассе.
@Sahuagin нет "нетипизированных" экземпляров во время выполнения, поэтому вы не можете помещать "нетипизированные элементы" ни во что, не понимая, что вы имеете в виду.
@SaebAmini, извините, под "нетипизированными" я подразумеваю членов, которые не используют параметр универсального типа. все, что не связано с универсальным типом, может быть помещено в базовый класс (или интерфейс), а затем вы можете использовать эти части объектов без преобразования типов. вам потребуется только приведение, чтобы использовать общие строго типизированные члены. (часто я также помещаю в базу «нетипизированные» версии общих членов, которые возвращают object или что-то подобное.
Этот ответ действительно открывает целый мир.
Следуя ответу Леппи, почему бы не сделать MetaData интерфейсом:
public interface IMetaData { }
public class Metadata<DataType> : IMetaData where DataType : struct
{
private DataType mDataType;
}
Может кто-нибудь сказать мне, почему этот подход лучше?
Поскольку общие функции не используются - зачем тогда тратить на это базовый класс? Достаточно интерфейса
Поскольку вы можете реализовать интерфейсы в struct.
Однако наследование классов с использованием виртуальных методов примерно в 1,4 раза быстрее, чем у интерфейсных методов. Поэтому, если вы планируете реализовать какие-либо неуниверсальные (виртуальные) методы / свойства MetaData в MetaData <DataType>, выберите абстрактный класс, а не интерфейс, если производительность вызывает беспокойство. В противном случае использование интерфейса может быть более гибким.
Я также использовал неуниверсальную версию, используя ключевое слово new:
public interface IMetadata
{
Type DataType { get; }
object Data { get; }
}
public interface IMetadata<TData> : IMetadata
{
new TData Data { get; }
}
Явная реализация интерфейса используется, чтобы позволить обоим членам Data:
public class Metadata<TData> : IMetadata<TData>
{
public Metadata(TData data)
{
Data = data;
}
public Type DataType
{
get { return typeof(TData); }
}
object IMetadata.Data
{
get { return Data; }
}
public TData Data { get; private set; }
}
Вы можете получить типы значений таргетинга версий:
public interface IValueTypeMetadata : IMetadata
{
}
public interface IValueTypeMetadata<TData> : IMetadata<TData>, IValueTypeMetadata where TData : struct
{
}
public class ValueTypeMetadata<TData> : Metadata<TData>, IValueTypeMetadata<TData> where TData : struct
{
public ValueTypeMetadata(TData data) : base(data)
{}
}
Это можно распространить на любые общие ограничения.
+1 только потому, что вы показываете, как его использовать (DataType и object Data очень помогли)
Я вроде не умею писать например Deserialize<metadata.DataType>(metadata.Data);. Это говорит мне не может разрешить метаданные символа. Как получить DataType, чтобы использовать его для универсального метода?
Интересно, есть ли реальная польза от подходов, описанных в приведенных ниже ответах, по сравнению с простым использованием
List<object>? Они не прекратят упаковку / распаковку, они не устранят необходимость в кастинге, и, в конечном итоге, вы получите объектMetadata, который ничего не говорит вам о самомDataType, я искал решение для решения этих проблем. Если вы собираетесь объявить интерфейс / класс, просто для того, чтобы иметь возможность поместить реализующий / производный универсальный тип в общий список, просто как отличается - это то, чем использованиеList<object>, кроме бессмысленного слоя?