开发者

The same property name but different return type in a generic list

Beginner's question: How to implement a generic list List<Item> returning items with a property named Data but returning different types for different subclasses? I started building the following hierarchy, but that does not lead to the goal.

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

I create a bunch of instances of ItemText and ItemImage classes and add them t开发者_运维知识库o a generic List<Item> list. However once I go through the list and want to retrieve the Data property it is not accessible as (obviously) it was implemented only in ItemGeneric<TData> class hierarchy level and not in the Item class.

I would like to solve this problem without using System.Object to avoid casting.

Is there any common pattern for solving this problem?


Not 100% sure if I understand the problem.

I usually use an interface with an untyped property:

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>
{

}

Then you can have alist of UntypedItems

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

You can't avoid casting or objects when you want to handle different types in the same list. You just can make clear what you are doing.


If you perform some functionality on typed data outside the containing class, then you'll need to know the type upfront.

Not nice:

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

You can resolve this by moving the functionality into the class containing the data.

(see encapsulation)

So, you could use your list like so:

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

which means you'll need a DoStuff on your Item class:

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

..and can implement that on your ItemGeneric:

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

    public override void DoStuff()
    {
        //do generic typed stuff here
        Console.WriteLine(Data);
    }
}


Something like this?

public class ItemGeneric<T> {

  private List<T> data;

}

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

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

In Java you can define the superclass as a generic type T, I don't know how it works in C#

public class ItemGeneric<T extends IData> {

 private List<T> data;
}


This is how you create a function in BaseClass that returns the collection of DerivedTypes when called from an object of type derivedclass, no magic just Generics. This example talks about HashSet, in your case it could be any type you want.

//**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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜