【问题标题】:Linq Where Condtion For Different Types不同类型的 Linq Where 条件
【发布时间】:2015-03-03 15:02:55
【问题描述】:

我有一个从 ProfileBase 派生的列表。这个列表可以包含 Profile,,DynamicViewProfile 的一个实例,因为它们都是从 ProfileBase 派生的

但如果项目类型是 DynamicViewProfile,我必须使用 NodeName,如果是 Profile,那么我应该使用 DocName

profileListsForSearch = profileLists.Where(stringToCheck =>
((Profile)stringToCheck).DocName.Contains(searchBar.Text)).ToList();

所以这是用于配置文件的,没关系,但如果列表包含 DynamicViewProfile 对象,那么我有一个例外,因为 docname 为空,我需要获取 NodeName

希望我的问题很清楚

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    这里的 LINQ 没有什么特别之处 - 您基本上可以编写与平时相同的代码,使用 isas

    string searchText = searchBar.Text;
    profileListsForSearch = profileLists
        .Where(profile =>
            profile is Profile 
            ? ((Profile)profile).DocName.Contains(searchText)
            : ((DynamicViewProfile)profile).NodeName.Contains(searchText))
        .ToList();
    

    假设这些是唯一涉及的两种类型。如果您的列表包含其他类型,您将获得InvalidCastException

    但是,这很丑 - 感觉就像 ProfileBase 应该公开一些指示通用名称的属性或方法 - 然后可以实现在 Profile 中返回 DocName 和在 @987654329 中返回 NodeName @。那么你只需要:

    string searchText = searchBar.Text;
    profileListsForSearch = profileLists
        .Where(profile => profile.Name.Contains(searchText))
        .ToList();
    

    在添加ProfileBase 的新子类方面,它也是面向未来的——通常更清洁地使用多态性。每次您需要强制转换时——尤其是有条件地强制转换为一件事或另一件事时——考虑一个通用方法/属性是否可行以使其更清洁。

    【讨论】:

    • 非常感谢您的解释
    • 天哪,你怎么能打字这么快。我开始认为你有一些“精神”键盘,而不是我们拥有的旧硬件:)
    • 正如我在另一条评论中所说,我无法更改类,因为它们来自 WCF 服务。你说得对,我可以有一个例外。但是类型是确定的,所以不会有问题。我知道我应该强制转换类型,但从来没有在 Where 条件下这样做的经验 :) 谢谢
    • @unbalanced:WCF 生成的类型是部分的,对吧?在这种情况下,您可以添加适当的属性以干净的方式进行操作...
    • 当然,我在 c# 中为 xamarin ios 使用 silverlight 工具 (slsvcutil) 生成了一个动态代理。但是我没有向这个动态代理添加任何东西,因为当服务更新时,我必须再次重新生成一个动态代理并且需要添加这个属性.. :) 那么这是一个更好的方法。谢谢
    【解决方案2】:

    您可以使用is 来检查对象,并使用ternary 运算符将条件应用于对象。

    var result = profileLists.Where(stringToCheck =>stringToCheck is Profile ? 
                               ((Profile)stringToCheck).DocName.Contains(searchBar.Text)
                               : ((DynamicViewProfile)stringToCheck).NodeName.Contains(searchBar.Text)).ToList();
    

    【讨论】:

    • 很高兴它有帮助。编码愉快。
    【解决方案3】:
    profileListsForSearch = profileLists.Where(p => 
    {
      if(p is Profile) return ((Profile)p).DocName.Contains(searchBar.Text));
      if(p is DynamicViewProfile) return ((DynamicViewProfile)p).NodeName.Contains(searchBar.Text)); 
      return false; 
    }).ToList();
    

    您可以检查类型。但这实际上只意味着您的类层次结构被破坏了。如果您派生,则永远不应强迫您显式检查类型。

    相反,您可以在基类中拥有一个名为FilterText 的属性,该属性由基类实现为return DocName;,派生类实现为return NodeName;。那么您的代码将如下所示:

    profileListsForSearch = profileLists.Where(p => p.FilterText.Contains(searchBar.Text)).ToList();
    

    【讨论】:

    • 感谢您的解释,但我无法更改类,因为它来自网络服务
    猜你喜欢
    • 2018-04-30
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多