Требуются предложения со списками или перечислителями T при наследовании от универсальных классов

StackOverflow https://stackoverflow.com/questions/53395

  •  09-06-2019
  •  | 
  •  

Вопрос

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

Абстрактный класс:

public interface IOtherObjects;

public abstract class MyObjects<T> where T : IOtherObjects
{
   ...

   public List<T> ToList()
   {
       ...
   }
}

Дети:

public class MyObjectsA : MyObjects<OtherObjectA> //(where OtherObjectA implements IOtherObjects)
{


}

public class MyObjectsB : MyObjects<OtherObjectB> //(where OtherObjectB implements IOtherObjects)
{


}

Возможно ли, выполняя цикл по коллекции MyObjects (или другой подобной группировке, универсальной или иной), затем использовать для ТоЛист способ проведения Мои объекты базовый класс, поскольку на данный момент мы конкретно не знаем тип T.

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

Редактировать @Sara, меня интересует не конкретный тип коллекции, это может быть список, но все же метод ToList каждого экземпляра относительно непригоден для использования без анонимного типа)

@aku, верно, и этот вопрос может быть относительно гипотетическим, однако возможность извлекать и работать со списком из T объектов, зная только их базовый тип, была бы очень полезна.То, что ToList возвращает список базовых типов, было одним из моих обходных путей

Редактировать @ все:До сих пор это была именно та дискуссия, на которую я надеялся, хотя она в значительной степени подтверждает все, что я подозревал.Пока всем спасибо, но кто-нибудь еще, не стесняйтесь вносить свой вклад.

Редактировать@Rob, да, это работает для определенного типа, но не тогда, когда тип известен только как список IOtherObjects.

@Роб Снова Спасибо.Обычно это был мой неуклюжий обходной путь (без неуважения :) ).Либо это, либо использование функции ConvertAll для понижения через делегат.Спасибо, что нашли время разобраться в проблеме.

УТОЧНЯЮЩЕЕ РЕДАКТИРОВАНИЕ на случай, если я что-то немного перепутал

Чтобы быть более точным, (возможно, я допустил, чтобы моя последняя реализация этого стала слишком сложной):

допустим, у меня есть 2 типа объектов: B и C, наследующие от объекта A.

Появилось много сценариев, где из списка B или списка C, или, в других случаях, из списка того и другого, но я не знаю, какой именно, если я нахожусь в базовом классе, мне нужен менее конкретный список A.

Приведенный выше пример был разбавленным примером Список Менее специфичных последнее воплощение проблемы.

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

@Роб Еще Раз и Сара

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

Фактический дизайн нашей системы и использование в ней дженериков (и я могу сказать это без тени предвзятости, поскольку я был лишь одним из участников разработки) были выполнены хорошо.Именно когда я работал с core API, я сталкивался с ситуациями, когда я был не в той области, чтобы делать что-то просто, вместо этого мне приходилось справляться с ними немного менее элегантно, чем мне хотелось бы (пытаясь либо быть умным, либо, возможно, ленивым - я приму любой из этих ярлыков).

Мое отвращение к тому, что я назвал скоплением, в значительной степени заключается в том, что нам требуется выполнить цикл по нашему набору записей просто для преобразования объектов в их базовое значение, что может привести к снижению производительности.

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

Это было полезно?

Решение

Если у вас есть

class B : A
class C : A

И у вас есть

List<B> listB;
List<C> listC;

который вы хотите рассматривать как список родительского типа

Тогда вам следует использовать

List<A> listA = listB.Cast<A>().Concat(listC.Cast<A>()).ToList()

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

зачем вам коллекция MyObjects?Есть ли какая-то конкретная причина, по которой у вас нет Списка?

В вашем случае MyObjectsA и MyObjectsB не имеют общего предшественника.Универсальный класс является шаблоном для другой классы не являются обычным базовым классом.Если вы хотите иметь общие свойства в разных классах, используйте интерфейсы.Ты не можешь позвонить ТоЛист в цикле, потому что он имеет разную сигнатуру в разных классах.Вы можете создать ToList, который возвращает Объекты скорее, чем конкретный тип.

Вероятно, вы все еще можете получить доступ к методу ToList(), но поскольку вы не уверены в типе, не сработает ли это?

foreach(var myObject in myObjectsList)
    foreach(var obj in myObject.ToList())
        //do something

Конечно, это будет работать только на C # 3.0.

Обратите внимание, что использование var предназначено просто для устранения требования знать, какой тип содержат списки;в отличие от комментариев Фрэнка о том, что у меня есть иллюзии, что var сделает набор текста динамичным.

Хорошо, я в замешательстве, следующий код отлично работает для меня (любопытство взяло верх надо мной!):

// Original Code Snipped for Brevity - See Edit History if Req'd

Или я что-то пропустил?

Обновите Следующий ответ от OP

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

Вы не можете вернуть типизированный список, если типы являются дочерними / разработчиками интерфейса - они не совпадают!Конечно, вы можете получить список элементов определенного типа из абстрактного списка следующим образом:

    public List<OfType> TypedList<OfType>() where OfType : IOtherObjects
    {
        List<OfType> rtn = new List<OfType>();

        foreach (IOtherObjects o in _objects)
        {
            Type objType = o.GetType();
            Type reqType = typeof(OfType);

            if (objType == reqType)
                rtn.Add((OfType)o);
        }

        return rtn;
    }

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

Еще Одно обновление:D

Верно, итак, похоже, что вы хотите / нуждаетесь в возможности получить типизированный список или базовый список yes?

Это сделало бы ваш абстрактный класс похожим на этот - вы можете использовать ToList для получения конкретного типа или ToBaseList() для получения списка типов интерфейса.Это должно сработать в любых сценариях, которые у вас есть.Помогает ли это?

public abstract class MyObjects<T> where T : IOtherObjects
{
    List<T> _objects = new List<T>();

    public List<T> ToList()
    {
        return _objects;
    }

    public List<IOtherObjects> ToBaseList()
    {
        List<IOtherObjects> rtn = new List<IOtherObjects>();
        foreach (IOtherObjects o in _objects)
        {
            rtn.Add(o);
        }
        return rtn;
    }
}

Обновление №3

На самом деле это не "неуклюжий" обходной путь (не сочтите за неуважение) - это единственный способ сделать это..Я думаю, что более серьезная проблема здесь - это проблема дизайна / grok.Вы сказали, что у вас есть проблема, и этот код решает ее.Но если вы ожидали сделать что-то вроде:

public abstract class MyObjects<T> where T : IOtherObjects
{
    List<T> _objects = new List<T>();

    public List<IOtherObjects> Objects
    { get { return _objects; } }
}
#warning This won't compile, its for demo's sake.

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

Недавно я обнаружил, что

List<A>.Cast<B>().ToList<B>()

закономерность.

Это делает именно то, что я искал,

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

interface IMyObjects : IEnumerable<IOtherObjects> {}
abstract class MyObjects<T> : IMyObjects where T : IOtherObjects {}

IEnumerable<IMyObjects> objs = ...;
foreach (IMyObjects mo in objs) {
    foreach (IOtherObjects oo in mo) {
        Console.WriteLine(oo);
    }
}

(Очевидно, я предпочитаю Перечислимые значения спискам.)

или Просто используйте правильный динамический язык, такой как VB.:-)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top