简体   繁体   中英

Return specific type in generic method depending on enum value without Reflection or dynamic during runtime

I have a non-generic IList which i would like to cast depending on an enum value during runtime.

I can not change the type of the non-generic IList in the implementation , because it is library code.

Also i do not want to use Reflection (because it is slow) or the dynamic keyword (because it is unsafe and could lead to mistakes down the road).

In the Library Code there is following class:

public class ListView //THIS IS LIBRARY CODE AND CAN NOT BE CHANGED
{
  public IList itemsSource { get; set; }
}

Then in my CustomListView class which inherits from ListView i want to cast the itemsSource to the appropiate class depending on ItemType.

Another limitation is that CustomListView can not be generic (dictated by the library we use)

public class CustomListView : ListView
{
    public dynamic GetItems()
    {
        switch (ItemType)
        {
            case ItemType.A:
              return itemsSource.Cast<A>().ToList();
            case ItemType.B:
              return itemsSource.Cast<B>().ToList();
            default:
              throw new InvalidOperationException("Not supported");
        }
    }
}

But i want it to directly return the correct type instead of using dynamic.

Something like (the code below does not work:):

public IList<T> GetItems(ItemType itemType) //The type of T should change depending on what i return
{
    switch (ItemType)
    {
        case ItemType.A:
          return itemsSource.Cast<A>().ToList();
        case ItemType.B:
          return itemsSource.Cast<B>().ToList();
        default:
          throw new InvalidOperationException("Not supported");
    }
}

How would i implement that?

Edit/Appendage

As you guys pointed out i should clarify some things.

Class A and B do indeed have the same base class. But i want to be able to not cast it from the base type again (because i already cast it in the GetItems() method and also the value of ItemType is known).

I want to be able to do following

IList<A> aItems = listView.GetItems()

Without casting.

Think about how this method would be used:

ItemType itemType = ...;
var x = listView.GetItems(itemType);

The value of itemType could be A , or it could be B . So what should the type of x be? It's either IList<A> , or IList<B> , and the only way to express that is to use a type that both IList<A> and IList<B> inherit from, which takes us back to IList . If you don't know the type that you want at compile time, then there is not much point trying to change the return type to something more specific, because you will not be able to access it as the more specific type without reflection.

If you do know the type that you want at compile time, then provide overloads of the method that return the desired type:

public IList<A> GetAItems() { ... }
public IList<B> GetBItems() { ... }

How do you expect to use such method? The type parameter is set by the caller of the method. Setting type parameter from withing the method is not possible. Please, specify the usage.

You can try these:

IList<T> GetItems<T>(ItemType itemType)
{
    switch (itemType)
    {
        case ItemType.A:
          return (IList<T>)(IList)(itemsSource.Cast<A>().ToList());
        case ItemType.B:
          return (IList<T>)(IList)(itemsSource.Cast<B>().ToList());
        default:
          throw new InvalidOperationException("Not supported");
    }
}
IList GetItems(ItemType itemType)
{
    switch (itemType)
    {
        case ItemType.A:
          return itemsSource.Cast<A>().ToList();
        case ItemType.B:
          return itemsSource.Cast<B>().ToList();
        default:
          throw new InvalidOperationException("Not supported");
    }
}

Or, as suggested by @Qwertyluk in comments, something like this:

private IList<object> GetItems(ItemType itemType)
{
    
    switch (itemType)
    {
        case ItemType.A:
        case ItemType.B:
          return itemsSource.Cast<object>().ToList();
        default:
          throw new InvalidOperationException("Not supported");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM