C# универсальный список универсального списка нескольких типов

Вот абстракция и упрощение моей проблемы:

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

public class Box<T> {}

затем в классе Поля я хочу иметь универсальный список игрушек, но каждая игрушка, содержавшая в поле, будет иметь универсальный тип:

public class Box<T>
{
    public List<Toy> = new List<Toy>();
    public bool Whatever;

    [member functions, constructors...]
    [The member functions will depend on T]
}

Класс Игрушек будет похож на это:

public class Toy<T> where T : struct //T is any type
{
    public List<T> = new List<T>();
    public string Name;
    public string Color;

    [member functions, constructors...]
}

Я хочу смочь создать, Играет со многими различными типами, и затем вставьте их в Поле с другим указанным типом. Затем я хотел бы смочь добавить поля, вместе возвращая Поле с самым большим типом.

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

Любая помощь, которую кто-либо мог оказать, будет очень цениться.

Решение может быть в C# 4.0.

Возможное будущее разъяснение:

Я хочу, чтобы Toy была универсальна и приняла аргумент при инстанцировании, потому что у Toy должен также быть Список как у участника.

Вложенный Список в Игрушке является моей основной проблемой. Я затем хочу список в Поле, которое содержит Игрушки, но каждая игрушка имеет как конструктор другого типа.

Обновление:

Я зафиксировал Поле для Упаковки, который был опечаткой.

Обновление 2:

Toy<plastic> tyPlastic = new Toy<plastic>("Name1", Blue, new plastic[] {0xFFEE00, 0xF34684, 0xAA35B2});
Toy<wood> tyWood = new Toy<wood>("Name2", Grain, new wood[] {a1, f4, h7});

Box<plastic> bxBox = new Box<plastic>();//The Box has the ability to hold both plastic and wood toys.  Plastic > Wood > Paper

Финал: Я закончил тем, что удалил требование для Поля для дженерика. Я затем использовал отражение для создания Toy с динамическим контролем типов. Спасибо все.

12
задан Moslem Ben Dhaou 4 July 2014 в 09:12
поделиться

4 ответа

Код, который Вы строите, будет лучше всего понятен, если он хорошо моделирует реальность.

Способом моделирования "A из B" является использование дженериков. Набор видов коробок, в которых может содержаться один вид вещей, будет смоделирован как Box. Коробка, в которой могут храниться только игрушки, будет Box. Набор видов коробок, которые могут вмещать только один вид вещей, и которые должны быть игрушками, был бы Box, где T : Toy.

Пока все хорошо. Но концепция Toy ни к чему не относится в реальной жизни. У вас может быть коробка печенья или коробка игрушек, но у вас нет игрушки с печеньем, игрушки с куклами или игрушки с жирафами. Понятие "игрушка" не имеет никакого смысла, поэтому не смоделируйте его .

Более разумной вещью для моделирования было бы "существует общий класс вещей, называемых игрушками". Нет ни одной вещи, которая была бы просто игрушкой; каждая игрушка является более специфическим видом игрушки. Шар - это игрушка. Кукла - это игрушка". Так смоделируйте:

abstract class Toy {}
class Doll : Toy {}
class Ball : Toy {}

Вы сказали

Я хочу, чтобы Игрушка была универсальной и принимала аргументы на собственном примере, потому что Игрушка также должна иметь список в качестве члена.

Почему? У игрушки нет списка вещей . Так что не смоделируйте это. Скорее, коробка логически моделируется как список игрушек, которые находятся внутри коробки. (Или, так как коробка обычно не применяет порядок, а коробка содержит только уникальные игрушки, возможно, лучше было бы множество игрушек.)

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

OK. Итак, операция на Box - это void Insert(T item). Вы можете положить игрушку в коробку с игрушками, вы можете положить куклу в коробку с куклами, но вы не можете положить шарик в коробку с куклами.

Тогда я хотел бы иметь возможность складывать коробки вместе, возвращая коробку с самым большим типом.

Нужно более тщательно определить "самый большой тип". Если вы добавите коробку с куклами в коробку с шариками, то очевидно, что результат не будет ни коробки с шариками, ни коробки с куклами. В результате получится коробка с игрушками.

Вот как я это смоделирую. У нас уже есть иерархия игрушек. Я бы продолжил, сказав, что коробка Т реализуется как набор ее содержимого, и обеспечивает последовательность ее содержимого.

// Haven't actually compiled this.
class Box<T> : IEnumerable<T>
{
    private HashSet<T> set = new HashSet<T>();
    public Insert(T item) { set.Add(item); }
    public IEnumerator<T> GetEnumerator() { return set.GetEnumerator(); }
    public IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }

Пока все очень скучно. Теперь перейдем к интересному моменту. Это хорошо работает только в C# 4 .

    public static Box<T> MergeBoxes(IEnumerable<T> box1, IEnumerable<T> box2)
    {
        Box<T> box = new Box<T>();
        foreach(T item in box1) box.Insert(item);
        foreach(T item in box2) box.Insert(item);
        return box;
    }
}

Теперь можно сказать

Box<Doll> dollbox = new Box<Doll>() { new Doll() };
Box<Ball> ballbox = new Box<Ball>() { new Ball() };
Box<Toy> toybox2 = Box<Toy>.MergeBoxes(ballbox, dollbox);

Результатом слияния коробки с куклами с коробкой с шариками является коробка с игрушками.

Этот последний бит работает только потому, что IEnumerable является ковариантом в C# 4. В C# 3 это было бы сложнее сделать правильно; вы должны сделать что-то вроде:

Box<Toy> toybox2 = Box<Toy>.MergeBoxes(ballbox.Cast<Toy>(), dollbox.Cast<Toy>());

Имеет ли это смысл?

.
27
ответ дан 2 December 2019 в 05:03
поделиться

Ваша самая последняя строка «Каждая игрушка имеет другой конструктор», подразумевает, что вам нужно либо класс базы игрушек, с каждой конкретной игрушкой наследующуюся из этого класса:

public abstract class Toy{} // abstract base class

public class Ball : Toy
{
    public Ball(){} // Ball constructor
}

или интерфейс для определения Общая игрушка с каждым конкретным типом игрушки, реализующая интерфейс ... Либо интерфейс, либо базовый класс может определить общий список.

Причина, по которой вам нужно, это то, что если вы используете класс Single для всех типов игрушек , то вы не сможете изменить конструктор на основе типа .. , Это просто не поддерживает поведение.

0
ответ дан 2 December 2019 в 05:03
поделиться

Я не уверен, что это то, что вы на самом деле хотите делать, так как это немного взлома. Если вы хотите перечислены списки каждого мыслимого типа игрушки, включая коробку, возможно, не знают, вам нужно будет использовать ваши общие параметры, чтобы отфильтровывать правильные игрушки. Я не рекомендую сделать это, если ящик не является просто пустым сланцом для набивки общего в доске (например, Blackboard ).

Например, вы можете иметь только один список <объект> и все методы проверки, если содержимое имеет правильный тип перед манипулированием их. Вы также можете использовать словарь , чтобы пропустить термин с терминной шагом фильтрации, но вызвать некоторые проблемы с наследством (список животных не будет включать в список вещей, добавленных в список жирафов).

Вот простая реализация подхода словаря:

public class MultiGenericList
{
    private readonly Dictionary<Type, Object> map = new Dictionary<Type,Object>();

    public List<T> GetList<T>()
    {
        if (!this.map.ContainsKey(typeof(T))) this.map.Add(typeof(T), new List<T>());
        return (List<T>)this.map[typeof(T)];
    }
}

Вы можете адаптировать этот код для ограничения списков определенного типа, и вы можете адаптировать его дальше, чтобы вы могли присоединиться к спискам, которые имеют общий базовый тип. Это может выглядеть так:

MultiGenericList<T> Join<C1, C2, T>(MultiGenericList<C1> child1, 
                                    MultiGenericList<C2> child2) where C1 : T, C2 : T
{
    ...
}
1
ответ дан 2 December 2019 в 05:03
поделиться

Цитирую MSDN:

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

Учитывая ваше описание, ближайшим объектом, к которому можно было бы применить, будет Ящик, но опять же, вы знаете, что он будет содержать Игрушки, и что у него максимальный Размер Игрушек, и что у Игрушек есть тип (Мяч, Лошадь...). Возможно, я ошибаюсь, но, возможно, не стоит использовать дженерики. Я думаю что-то вроде:

    public class Box
    {
        public ToyType MaxType { get; set; }
        public List<Toy> Toys = new List<Toy>();

        public void Add(Toy toy)
        {
            if (toy.Type.Size <= MaxType.Size) //if its not larger, or whatever compatibility test you want
                Toys.Add(toy);
        }
    }

    public class Toy
    {
        public ToyType Type { get; set; }
        public Toy(ToyType type)
        {
            Type = type;
        }  
    }

    public abstract class ToyType
    {
        public abstract string TypeName { get; set; }
        public abstract int Size { get; set; }
    }

Если только у вас нет особой причины использовать дженерики.

1
ответ дан 2 December 2019 в 05:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: