我有两个类,CheckboxItemsList
扩展了通用列表,CheckboxItems
包含类型为CheckboxItem
的对象列表。
我想使用LINQ来根据其CheckboxItems对象的属性过滤CheckboxItemsList。但是返回类型总是一个通用列表,但我希望它是一个CheckboxItemsList。
所以我想基本的问题是,linq可以返回一个与它开头的相同类型的列表吗?由于我不能将基类强制转换为派生类,除了遍历linq查询的结果并逐行重建派生列表对象之外,我还有其他选择吗?并不是说这是世界末日,但我对linq相对较新,并且想知道有更好的方法可以做到。
我想要的是什么:
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed);
(显然不起作用,因为查询将返回List<CheckboxItems>
,而不是CheckboxItemsList
)
对象,通常是:
public class CheckboxItemsList: List<CheckboxItems>
{
// does not add any fields, just access methods
}
public class CheckboxItems : IEnumerable<CheckboxItem>
{
public long PrimaryKey=0;
protected CheckboxItem[] InnerList;
public bool Changed
{
get {
return (InnerList.Any(item => item.Changed));
}
}
....
}
答案 0 :(得分:1)
不,这不是开箱即用的。您需要添加代码才能执行此操作。
例如,您可以添加如下构造函数:
public CheckboxItemsList(IEnumerable<CheckboxItems> checkboxItems) {
// something happens
}
然后你可以说
CheckboxItemsList newList = new CheckboxItemsList(
MyCheckboxItemsList.Where(item => item.Changed)
);
此外,您可以添加类似的扩展方法
static class IEnumerableCheckboxItemsExtensions {
public static ToCheckboxItemsList(
this IEnumerable<CheckboxItems> checkboxItems
) {
return new CheckboxItemsList(checkboxItems);
}
}
然后
CheckboxItemsList newList =
MyCheckboxItemsList.Where(item => item.Changed)
.ToCheckboxItemsList();
答案 1 :(得分:1)
LINQ适用于IEnumerable<T>
和IQueryable<T>
,所有LINQ操作(Where
,Select
)等的结果类型将返回其中一个。标准ToList
函数返回类型为List<T>
的具体列表,您可能需要提出一种扩展方法,例如:
public static CheckboxItemsList ToItemList(this IEnumerable<CheckboxItem> enumerable)
{
return new CheckboxItemsList(enumerable);
}
答案 2 :(得分:1)
您也可以使用“转换运算符”,如下所示:
public class CheckboxItemsList: List<CheckboxItems>
{
public static implicit operator CheckboxItems(IEnumerable<CheckboxItems> items)
{
var list = new CheckboxItemsList();
foreach (var item in items)
{
list.Add(item);
}
return list;
}
}
现在,以下代码可以使用。
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed);
来自MSDN:
包含implicit关键字的转换运算符声明引入了用户定义的隐式转换。隐式转换可以在各种情况下发生,包括函数成员调用,强制转换表达式和赋值。这将在第6.1节中进一步描述。
包含explicit关键字的转换运算符声明引入了用户定义的显式转换。显式转换可以在强制转换表达式中进行,并在第6.2节中进一步描述。
答案 3 :(得分:0)
不,没有内置方法可以做到这一点。您有两个主要选择:
在CheckboxItemsList
班级中添加一个IEnumerable<CheckboxItems>
或类似的构造函数。将该集合传递到IEnumerable<T>
的{{3}}。然后,该基础构造函数应该为您填充列表:
var newList =
new CheckboxItemsList(MyCheckboxItemsList.Where(item=>item.Changed));
// ...
public class CheckboxItemsList : List<CheckboxItems>
{
public CheckboxItemsList(IEnumerable<CheckboxItems> collection)
: base(collection)
{
}
}
创建一个采用IEnumerable<CheckboxItems>
或类似内容的扩展方法,并返回已填充的CheckboxItemsList
:
var newList = MyCheckboxItemsList.Where(item=>item.Changed)
.ToCheckboxItemsList();
// ...
public static class EnumerableExtensions
{
public static CheckboxItemsList ToCheckboxItemsList(
this IEnumerable<CheckboxItems> source)
{
var list = new CheckboxItemsList();
foreach (T item in source)
{
list.Add(item);
}
return list;
}
}
(当然,为了完整性,您可以实现这两个选项。扩展方法只会将其IEnumerable<CheckboxItems>
参数传递给构造函数,而不是手动循环并添加每个项目。)
答案 4 :(得分:0)
这是我想出的建议,建立在别人的各种建议之上。通用扩展方法:
public static T ToList<T>(this IEnumerable baseList) where T : IList,new()
{
T newList = new T();
foreach (object obj in baseList)
{
newList.Add(obj);
}
return (newList);
}
所以现在我可以做我想做的事:
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed)
.ToList<CheckboxItemsList>();
我发现了另一个非常明显的解决方案,这对于派生列表类具有我需要在新列表中维护的字段属性的情况也很有用。
只需创建派生列表类的新实例,然后使用AddRange填充它。
// When created with a CheckboxItemsList parameter, it creates a new empty
// list but copies fields
CheckboxItemsList newList = new CheckboxItemsList(OriginalList);
newList.AddRange(OriginalList.Where(item => item.Changed));