【问题标题】:Filtering nested lists with nullable property过滤具有可为空属性的嵌套列表
【发布时间】:2019-03-31 19:26:43
【问题描述】:

假设我有以下类结构

public class EmailActivity {
    public IEnumerable<MemberActivity> Activity { get; set; }
    public string EmailAddress { get; set; }
}

public class MemberActivity {
    public EmailAction? Action { get; set; }
    public string Type { get; set; }
}

public enum EmailAction {
    None = 0,
    Open = 1,
    Click = 2,
    Bounce = 3
}

我希望根据MemberActivity 的存在过滤EmailActivity 对象列表,其中非空EmailAction 匹配提供的EmailAction 匹配列表。我只想将 EmailAddress 属性返回为List&lt;string&gt;

这是我所知道的

List<EmailAction> activityTypes; // [ EmailAction.Open, EmailAction.Bounce ]

List<string> activityEmailAddresses =
    emailActivity.Where(
        member => member.Activity.Where(
            activity => activityTypes.Contains(activity.Action)
        )
    )
    .Select(member => member.EmailAddress)
    .ToList();

但是我收到一条错误消息“CS1503 参数 1:无法从 'EmailAction 转换?'到“电子邮件操作””

如果然后修改activityTypes 以允许空值List&lt;EmailAction?&gt; 我得到以下“CS1662 无法将 lambda 表达式转换为预期的委托类型,因为块中的某些返回类型不能隐式转换为委托返回类型”。

问题是嵌套的.Where 返回一个列表,但父级.Where 需要一个布尔结果。我该如何解决这个问题?

我意识到我可以使用嵌套循环,但我正在努力提高我的 C# 技能!

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    使用List.Contains 在性能方面并不理想,HashSet 是一个更好的选择,如果您想在包含搜索到的操作之一时立即选择电子邮件地址,您可以使用Any

    var activityTypes = new HashSet<EmailAction>() { EmailAction.Open, EmailAction.Bounce };
    
    List<string> activityEmailAddresses =
        emailActivity.Where(
            member => member.Activity.Any(
                activity => activity.Action.HasValue && 
                            activityTypes.Contains(activity.Action.Value)
        )
    )
    .Select(activity => activity.EmailAddress)
    .ToList();
    

    【讨论】:

      【解决方案2】:

      您想使用AllAny 取决于您是否需要每个匹配项或至少一个匹配项...

      HashSet<EmailAction> activityTypes = new HashSet<EmailAction> { EmailAction.None };
      
      var emailActivity = new List<EmailActivity>
      {
          new EmailActivity { Activity = new List<MemberActivity>{ new MemberActivity { Action = EmailAction.None } }, EmailAddress = "a" },
          new EmailActivity { Activity = new List<MemberActivity>{ new MemberActivity { Action = EmailAction.Click } }, EmailAddress = "b" }
      };
      
      // Example with Any but All can be used as well
      var activityEmailAddresses = emailActivity
          .Where(x => x.Activity.Any(_ => _.Action.HasValue && activityTypes.Contains(_.Action.Value)))
          .Select(x => x.EmailAddress)
          .ToArray();
      // Result is [ "a" ] 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-12
        • 1970-01-01
        • 2023-03-31
        • 1970-01-01
        • 2021-04-06
        • 2021-10-29
        • 1970-01-01
        • 2016-06-11
        相关资源
        最近更新 更多