То же имя свойства, но другой тип возвращаемого значения в общем списке - PullRequest
3 голосов
/ 26 ноября 2009

Вопрос новичка: как реализовать общий список List<Item>, возвращающий элементы со свойством с именем Data, но возвращающий разные типы для разных подклассов? Я начал строить следующую иерархию, но это не ведет к цели.

abstract class Item
abstract class ItemGeneric<TData> : Item
class ItemText : ItemGeneric<string>
class ItemImage : ItemGeneric<Image>

Я создаю группу экземпляров классов ItemText и ItemImage и добавляю их в общий список List<Item>. Однако, как только я просматриваю список и хочу получить свойство Data, оно становится недоступным, поскольку (очевидно) оно было реализовано только на уровне иерархии классов ItemGeneric<TData>, а не в классе Item.

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

Есть ли какой-нибудь общий способ решения этой проблемы?

Ответы [ 4 ]

1 голос
/ 30 сентября 2010

Если вы выполняете некоторые функции над типизированными данными вне содержащего класса, тогда вам нужно знать тип заранее.

Не приятно:

foreach (Item item in list)
{
    ItemGeneric<int> intItem = item as ItemGeneric<int>;
    if (intItem != null)
    {
        //do stuff
    }
}

Вы можете решить эту проблему, переместив функциональность в класс, содержащий данные.

(см. инкапсуляция )

Итак, вы можете использовать свой список следующим образом:

foreach (Item item in list)
{
    item.DoStuff();
}

, что означает, что вам понадобится DoStuff для вашего класса Item:

public abstract class Item
{
    public abstract void DoStuff();
}

.. и может реализовать это на вашем ItemGeneric:

public class ItemGeneric<T> : Item
{
    public T Data { get; set; }

    public override void DoStuff()
    {
        //do generic typed stuff here
        Console.WriteLine(Data);
    }
}
1 голос
/ 26 ноября 2009

Не уверен на 100%, понимаю ли я проблему.

Я обычно использую интерфейс с нетипизированным свойством:

interface IUntypedItem
{
  object UntypedData {get; }
}

interface IItem<T> : IUntypedItem
{
  T Data {get; set;}
}

class abstract ItemGeneric<T> : IItem<T>
{
  T Data { get; set; }
  object UntypedData { get { return Data; }}
}

class ItemText : ItemGeneric<string>
{

}

Тогда вы можете иметь список UntypedItems

List<IUntypedItem> list;
foreach (IUntypedItem item in list)
{
  // use item.UntypedData
  // or downcast to use typed property
}

Вы не можете избежать приведения типов или объектов, если хотите обрабатывать разные типы в одном и том же списке. Вы просто можете понять, что вы делаете.

0 голосов
/ 26 ноября 2009

Вот как вы создаете функцию в BaseClass, которая возвращает коллекцию DerivedTypes при вызове из объекта производного класса, никакой магии, только Generics. Этот пример говорит о HashSet, в вашем случае это может быть любой тип, который вы хотите.

//**The BaseClass**
public class BaseClass<T>
    where T : BaseClass<T>
{
    public HashSet<T> GetHashSet()
    {
        HashSet<T> hSet = new HashSet<T>();
        //create a HashSet<T>
        //do some work
        //and return;
        return hSet;
    }
}

//**The Derived Class**
public class DerivedClass : BaseClass<DerivedClass>
{
    //you have the method inherited.
}
0 голосов
/ 26 ноября 2009

Как то так?

public class ItemGeneric<T> {

  private List<T> data;

}

public class ItemText : ItemGeneric<String> { ... }

public class ItemImage : ItemGeneric<Image> { ... }

В Java вы можете определить суперкласс как универсальный тип T, я не знаю, как он работает в C #

public class ItemGeneric<T extends IData> {

 private List<T> data;
}
...