Reputation: 4602
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
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
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
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
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