Matt
Matt

Reputation: 4602

Select a Collection with same interface

If have following classen

public interface ISomething { int Id { get; set; } }
public class SomethingA : ISomething {...}
public class SomethingB : ISomething {...}

In another class I have following two lists:

List<SomethingA> aValues;
List<SomethingB> bValues;

My question is if there is a possibility to do something like this:

public List<ISomething> GetList(bool select) {
    return select ? aValues : bValues;
}

My goal is to use this as this:

GetList(true).Single(x => x.Id) // or
foreach (var value in GetList(false))
{
    value.Id = 18;
}
// anything else

UPDATE: I see, there are good possibilities. But is there also a way to also achieve the following?

GetList(true).Remove(myValue);

Upvotes: 0

Views: 76

Answers (4)

wezzix
wezzix

Reputation: 2124

The simplest solution may be using Linq Cast() like this:

    public List<ISomething> GetList(bool select)
    {
        return (List<ISomething>)(@select ? aValues.Cast<ISomething>() : bValues.Cast<ISomething>());
    }

I see, there are good possibilities. But is there also a way to also achieve the following? GetList(true).Remove(myValue);

To remove from the original lists, you are likely best of with a specialized Remove method on the class in question as others have suggested, as most solutions here return a copy of the original list. You may remove the element from a copy of the list quite easily like so, but I understand that's not what you are asking.

    var result = GetList(true);
    result.Remove(myValue);

Upvotes: 0

samy
samy

Reputation: 14962

I like the OfType extension because it returns the typed list you need

var listA = initialList.OfType<TypeA>(); //return List<TypeA>
var listB = initialList.OfType<TypeB>(); //return List<TypeB>

So in your case you start with

var aValues = List<ISomething>.OfType<SomethingA>()

and then you can iterate on whichever subcollection you need. Of course you are then working with a IEnumerable, but that can be converted implicitly back to a IEnumerable<ITest>.

If you want to filter out values, I would create explicit methods to remove them but it depends on what you need to achieve in the end (for example comparing on a Id instead of the whole object):

public IEnumerable<T> Remove<T>(this List<IDisposable> values, T valueToRemove) where T: IComparable
{
    return values.OfType<T>().Where(t => valueToRemove.CompareTo(t) != 0);
}

Upvotes: 0

Sriram Sakthivel
Sriram Sakthivel

Reputation: 73472

You can't return List<ISomething> because List<T> is not covariant and classes can't be. IEnumerable<T> is covariant, you may use it as readonly sequence.

Change the method to return IEnumerable<ISomething>

public static IEnumerable<ISomething> GetList(bool select)
{
    return select ? (IEnumerable<ISomething>)aValues :bValues;
}

Then do

var result = GetList(true).Single(x => x.Id == 0);
foreach (var value in GetList(false))
{
    value.Id = 18;
}

As for your update: If you like to remove the item you need to lose some flexibility. I.e Use non generic IList as the return type.

public static IList GetList(bool select)
{
    return select ? (IList)aValues : bValues;
}

Then do

IList list = GetList(true);
foreach (var value in list.OfType<ISomething>())//OfType or Cast can be used
{
    if (value.Id == 6)//Whatever condition
    {
        list.Remove(value);
        break;
    }
}

Upvotes: 2

WeSt
WeSt

Reputation: 2684

You can either use the .Cast<T> method like this:

if (select)
{
    return aValues.Cast<ISomething>().ToList();
}
else
{
    return bValues.Cast<ISomething>().ToList();
}

or add all items to a commong Lis() like this:

var ret = new List<ISomething>();
if (select)
{
    ret.AddRange(aValues);
}
else
{
    ret.AddRange(bValues);
}
return ret;

Since you only want to iterate it, I would write the method like this:

public IEnumerable<ISomething> GetList(bool select) {
    return select ? aValues.Cast<ISomething>() : bValues.Cast<ISomething>();
}

You can also look at this StackOverflow question.

Upvotes: -1

Related Questions