【问题标题】:Cast from filtered custom List<T> with LINQ使用 LINQ 从过滤后的自定义 List<T> 投射
【发布时间】:2009-10-12 01:46:16
【问题描述】:

我有一个继承自 Generic.List&lt;T&gt; 的自定义列表,如下所示:

public class TransferFileList<T> : List<TransferFile> { .. }

当我设置时('Files' 是TransferFileList&lt;T&gt;):

var files = uploadResponse.Files.Where(x => !x.Success).ToList()

files”对象解析为System.Collections.Generic.List&lt;TransferFile&gt;,而不是TransferFileList&lt;T&gt;,这是我所期望的,因为它是通过Where 过滤的内容,所以我怎样才能成功返回@ 列表987654330@ 进入“文件”?

我试过了:

var files = uploadResponse.Files.Where(x => !x.Success).ToList() 
as TransferFileList<TransferFile>;

但使用安全转换,它只是解析为 null。

谢谢大家。

【问题讨论】:

  • 如果“var files = uploadResponse.Files.Where(x => !x.Success)”你会得到什么?
  • @Kirk OP 将获得IEnumerable&lt;TransferFile&gt;
  • System.Linq.Enumerable+WhereListIterator`1[TransferFile]

标签: c# .net linq generics lambda


【解决方案1】:

首先,我要问你为什么要继承List&lt;T&gt;? 99% 的情况下这是个坏主意。

如果要扩展列表的功能,请使用扩展方法:

public static something PrintErrors(this List<TransferFile> list)
{
    //do your printing logic
}

回答:ToList()IEnumerable&lt;T&gt; 进行操作,并将序列的成员转换为相同类型的List。由于您从实现IEnumerable&lt;T&gt;List&lt;T&gt; 继承,所以那里会发生这种情况。

Where() 的工作方式相同 - 对 IEnumerable&lt;T&gt; 进行操作并返回 IEnumerable&lt;T&gt;

要像您一样获取一些类似列表的任意对象,您需要按顺序将项目添加到您的自定义列表中,如下所示:

var myFiles = new TransferFileList<TransferFile>();
myFiles.AddRange(originalFileList.Where(condition));

【讨论】:

  • 为什么 Rex 不好?希望我是 1% :) 我有一个 PrintErrors() 方法,该方法将我响应的任何附加错误作为打印友好的字符串返回。
  • @GONeale 因为当你从 List 继承时,没有什么能像你期望的那样工作,就像这种情况一样。请参阅我修改后的答案以获取替代方案。
  • Rex 在 x 方法上的观点非常好,但是它们可以触及实例变量吗?我不这么认为,因为它们存在于实例之外,所以我在 printErrors 中有这样一行:
    string internalErrorMessage = StoreErrorBase.GetMessage(file.Error);
    (file.Error) being an ' “TransferFile”实例上的“错误”属性。
  • @GONeale 列表上的扩展方法可以访问基础列表的所有公共成员以及列表中的所有项目。
  • 谢谢 Rex,我很不情愿地像你说的那样引入一个新的变量和新的列表赋值。如果它是首选方法没问题!
【解决方案2】:

您可以为IEnumerable&lt;TransferFile> 添加一个扩展方法来处理这种情况:

public static TransferFileList ToTransferFileList(
    this IEnumerable<TransferFile> files)
{
    return new TransferFileList(files);
}

// ...

var files = uploadResponse.Files.Where(x => !x.Success).ToTransferFileList(); 

这将为您提供TransferFileList 而不仅仅是List&lt;TransferFile&gt;。请注意您的as 返回null 的原因是因为TransferFileListList&lt;TransferFile&gt;,但在另一个方向上同样不成立。也就是说,您的 List&lt;TransferFile&gt; 不是 TransferFileList 对象。

我同意@RexM 的观点,即由于存在大量相关陷阱,应避免任何对List&lt;T&gt; 进行子类化的尝试。我建议使用 Composition(Has-A 而不是 Is-A)或坚持使用基类库集合。

【讨论】:

  • 我们不知道 TransferFileList 是否没有接受序列的 ctor,即使有,它只是在治疗症状而不是问题的原因。
  • 他可能真的需要TransferFileList 中的附加功能。我同意,尽管这种组合比继承更适合他。
【解决方案3】:

谢谢大家。

我喜欢 SLV 的扩展方式,但还有其他直接转换方式吗?

如果不是,我可能会采用我希望避免的恢复的内联方法:

var transferFiles = new TransferFileList<TransferFile>();
if (files != null) 
  transferFiles.AddRange(files);

【讨论】:

    猜你喜欢
    • 2014-10-16
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多