Требуются предложения со списками или перечислителями T при наследовании от универсальных классов - PullRequest
2 голосов
/ 10 сентября 2008

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

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

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 (или другой подобной группировки, универсальной или другой), чтобы затем использовать в ToList метод базового класса MyObjects , как мы это делаем конкретно не знаю тип Т на данный момент.

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

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

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

РЕДАКТИРОВАТЬ @ all: До сих пор это была дискуссия, на которую я надеялся, хотя она в значительной степени подтверждает все мои подозрения. Спасибо всем до сих пор, но кто-либо еще, не стесняйтесь вводить.

РЕДАКТИРОВАТЬ @ Роб, Да, это работает для определенного типа, но не тогда, когда тип известен только как список объектов IOtherObject.

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

ПРАВИЛА КВАЛИФИКАЦИИ на случай, если я немного запутался

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

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

Многие сценарии представили себя где, из Списка B или Списка C, или в других случаях из Списка того или другого - но я не знаю, что, если я нахожусь в базовом классе, мне нужно меньше Конкретный список А.

Приведенный выше пример представляет собой разбавленный пример последнего воплощения проблемы Список .

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

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

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

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

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

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

Ответы [ 7 ]

2 голосов
/ 10 сентября 2008

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

2 голосов
/ 10 сентября 2008

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

1 голос
/ 17 сентября 2008

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

class B : A
class C : A

И у вас есть

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

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

Тогда вы должны использовать

List<A> listA = listB.Cast<A>().Concat(listC.Cast<A>()).ToList()
1 голос
/ 10 сентября 2008

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

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

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

Обновить после ответа от OP

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

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

    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

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

Это сделает ваш абстрактный класс похожим на это - вы можете использовать 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

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

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.

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

1 голос
/ 10 сентября 2008

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

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

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

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

0 голосов
/ 19 сентября 2008

Я недавно нашел

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

рисунок.

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

0 голосов
/ 10 сентября 2008

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...