选择具有相同界面的集合

时间:2014-08-27 14:13:19

标签: c# collections

如果有以下classen

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

在另一个课程中,我有以下两个列表:

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

我的问题是,是否有可能做这样的事情:

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

我的目标是将其用作:

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

更新: 我知道,有很好的可能性。但是还有一种方法可以实现以下目标吗?

GetList(true).Remove(myValue);

4 个答案:

答案 0 :(得分:2)

您无法返回List<ISomething>,因为List<T>不是协变而类不能。 IEnumerable<T>是协变的,您可以将其用作只读序列。

更改方法以返回IEnumerable<ISomething>

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

然后做

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

至于您的更新:如果您想要删除该项目,您需要失去一些灵活性。即使用非泛型IList作为返回类型。

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

然后做

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;
    }
}

答案 1 :(得分:0)

最简单的解决方案可能是使用Linq Cast():

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

我知道,有很好的可能性。但是还有一种方法可以实现以下目标吗?   的GetList(真)卸下摆臂(myvalue的);

要从原始列表中删除,您可能最好使用其他人建议的类上的专门Remove方法,因为此处的大多数解决方案都会返回原始列表的副本。 您可以很容易地从列表副本中删除元素,但我知道这不是您所要求的。

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

答案 2 :(得分:0)

我喜欢OfType扩展程序,因为它会返回您需要的类型列表

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

所以在你的情况下,你从

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

然后你可以迭代你需要的任何子集合。当然,您正在使用IEnumerable,但可以隐式转换回IEnumerable<ITest>

如果你想过滤掉值,我会创建显式方法来删除它们,但这取决于你最终需要实现的目标(例如比较Id而不是整个对象):

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

答案 3 :(得分:-1)

您可以使用.Cast<T>方法,如下所示:

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

或将所有项目添加到commong Lis(),如下所示:

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

由于你只想迭代它,我会写这样的方法:

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

您还可以查看此StackOverflow question