C# - несколько универсальных типов в одном списке

Вероятно, это невозможно, но у меня есть такой класс:

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>());

Это вообще возможно?

Интересно, есть ли реальная польза от подходов, описанных в приведенных ниже ответах, по сравнению с простым использованием List<object>? Они не прекратят упаковку / распаковку, они не устранят необходимость в кастинге, и, в конечном итоге, вы получите объект Metadata, который ничего не говорит вам о самом DataType, я искал решение для решения этих проблем. Если вы собираетесь объявить интерфейс / класс, просто для того, чтобы иметь возможность поместить реализующий / производный универсальный тип в общий список, просто как отличается - это то, чем использование List<object>, кроме бессмысленного слоя?

Saeb Amini 17.11.2012 22:11

И абстрактный базовый класс, и интерфейс обеспечивают определенную степень контроля, ограничивая тип элементов, которые могут быть добавлены в список. Я также не могу понять, как в этом проявляется бокс.

0b101010 28.02.2014 00:06

Конечно, если вы используете .NET v4.0 или выше, ковариация - это решение. List<Metadata<object>> делает свое дело.

0b101010 28.02.2014 00:50

@ 0b101010 Я думал то же самое, но, к сожалению, для типов значений отклонение недопустимо. Поскольку OP имеет ограничение struct, здесь он не работает. Видеть

nawfal 07.07.2014 11:33

@ 0b101010, Оба ограничивают только ссылочные типы, любой встроенный тип значения и любую структуру все еще можно добавить. Кроме того, в конце у вас есть список ссылочных типов MetaData вместо ваших исходных типов значений без информации (время компиляции) о базовом типе значения каждого элемента, то есть эффективно «бокс».

Saeb Amini 30.09.2014 00:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
162
5
102 617
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий
public abstract class Metadata
{
}

// extend abstract Metadata class
public class Metadata<DataType> : Metadata where DataType : struct
{
    private DataType mDataType;
}

Ух ты! Я действительно не думал, что это возможно! Ты спасатель, чувак!

Carl 09.12.2008 18:37

+10 за это! Не знаю, зачем это компилируется .. Именно то, что мне нужно!

Odys 21.12.2011 02:45

У меня аналогичная проблема, но мой общий класс является наследником другого универсального класса, поэтому я не могу использовать ваше решение ... какие-либо идеи по исправлению этой ситуации?

Sheridan 08.08.2012 16:44

Есть ли в этом подходе преимущество по сравнению с простым List<object>? пожалуйста, посмотрите мой комментарий, опубликованный под вопросом OP.

Saeb Amini 17.11.2012 22:10

@leppie: Можно ли добавить в список несколько экземпляров Metadata?

Khoi 13.12.2015 11:47

@SaebAmini Кто-нибудь может ответить на вопрос Саеба? Объект по-прежнему будет упакован как Metadata, как и object. Я пытаюсь понять, почему бы вам просто не использовать List<object>,

oscilatingcretin 24.01.2016 00:54

@SaebAmini Список <объект> не показывает никаких намерений разработчику и не мешает разработчику выстрелить себе в ногу, ошибочно добавив в список какой-либо объект, не относящийся к метаданным. Используя List <MetaData>, можно понять, что должен содержать список. Скорее всего, у MetaData будут некоторые общедоступные свойства / методы, которые не были показаны в приведенных выше примерах. Доступ к ним через объект потребует громоздкого приведения.

Buzz 30.03.2016 19:10

@SaebAmini. С его помощью вы можете помещать «нетипизированные» члены в базовый класс и напрямую обращаться к ним через массив. только члены, связанные с универсальным типом, должны быть в подклассе.

Dave Cousineau 18.10.2016 22:08

@Sahuagin нет "нетипизированных" экземпляров во время выполнения, поэтому вы не можете помещать "нетипизированные элементы" ни во что, не понимая, что вы имеете в виду.

Saeb Amini 19.10.2016 01:15

@SaebAmini, извините, под "нетипизированными" я подразумеваю членов, которые не используют параметр универсального типа. все, что не связано с универсальным типом, может быть помещено в базовый класс (или интерфейс), а затем вы можете использовать эти части объектов без преобразования типов. вам потребуется только приведение, чтобы использовать общие строго типизированные члены. (часто я также помещаю в базу «нетипизированные» версии общих членов, которые возвращают object или что-то подобное.

Dave Cousineau 19.10.2016 01:18

Этот ответ действительно открывает целый мир.

jonathana 26.08.2020 19:37

Следуя ответу Леппи, почему бы не сделать MetaData интерфейсом:

public interface IMetaData { }

public class Metadata<DataType> : IMetaData where DataType : struct
{
    private DataType mDataType;
}

Может кто-нибудь сказать мне, почему этот подход лучше?

Lazlo 01.09.2010 21:46

Поскольку общие функции не используются - зачем тогда тратить на это базовый класс? Достаточно интерфейса

flq 04.09.2010 01:04

Поскольку вы можете реализовать интерфейсы в struct.

Damian Leszczyński - Vash 02.01.2012 00:42

Однако наследование классов с использованием виртуальных методов примерно в 1,4 раза быстрее, чем у интерфейсных методов. Поэтому, если вы планируете реализовать какие-либо неуниверсальные (виртуальные) методы / свойства MetaData в MetaData <DataType>, выберите абстрактный класс, а не интерфейс, если производительность вызывает беспокойство. В противном случае использование интерфейса может быть более гибким.

TamusJRoyce 05.04.2012 00:08

Я также использовал неуниверсальную версию, используя ключевое слово 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 очень помогли)

Odys 26.12.2011 23:04

Я вроде не умею писать например Deserialize<metadata.DataType>(metadata.Data);. Это говорит мне не может разрешить метаданные символа. Как получить DataType, чтобы использовать его для универсального метода?

Cœur 26.05.2014 13:01

Другие вопросы по теме