如何替换字典的 IF 语句? (C#,Linq)

Posted

技术标签:

【中文标题】如何替换字典的 IF 语句? (C#,Linq)【英文标题】:How to replace IF statements for dictionary? (C#, Linq) 【发布时间】:2020-11-19 05:28:20 【问题描述】:

我有一个 SampleObject 的相等比较器:

    public bool Equals(SampleObject x, SampleObject y)
    
        if (x == null)
        
            return y == null;
        

        if (y == null)
        
            return false;
        

        if (!string.Equals(x.SomeId, y.SomeId))
        
            return false;
        

        if (x.EventsList == null)
        
            return y.EventsList == null;
        

        if (y.EventsList == null)
        
            return false;
        

        return x.EventsList.OrderBy(e => e)
            .SequenceEqual(y.EventsList.OrderBy(e => e));
    

我想知道是否有办法替换字典中的所有 IF 子句?

【问题讨论】:

不是答案,而是观察:当 x.EventsList 和 y.EventsList 都为空时,您将它们视为相等 - 但当 x 和 y 都为空时,您将它们视为不相等。你是故意的吗? @MatthewWatson:我不这么认为:如果 x 和 y 都为 null,则 if (x == null) return y == null 将返回 true。莱蒂没有改变问题,不是吗? 你确定是指字典吗?它的关键/价值是什么?或者你是否在使用某种机制,你有某种可枚举的规则集,而第一个返回的规则会终止规则的枚举? 旁注:请避免null 用于集合,例如EventList;改用空的 @GWimpassinger Doh。 :) 当然你是对的。我需要增加我的字体大小... 【参考方案1】:

这是不可能的字典,但有一个列表。字典没有顺序,因此您不能保证您的检查以正确的顺序执行。我使用了一个元组列表,其中第一项是条件,第二项是返回值。您的代码如下:

public bool Equals(SampleObject x, SampleObject y)

var checks = new List<(Func<bool>,Func<bool>)>

    (() => x == null, () => y == null),
    (() => y == null, () => false),
    (() => !string.Equals(x.SomeId, y.SomeId), () => false),
    (() => x.EventsList == null, () => y.EventsList == null),
    (() => y.EventsList == null, () => false)
;
foreach(var entry in checks)

     if(entry.Item1.Invoke())
     
       return entry.Item2.Invoke();
     

return x.EventsList.OrderBy(e => e)
            .SequenceEqual(y.EventsList.OrderBy(e => e));

但我强烈建议保留您的原始版本,因为从我的角度来看,这种方法的可读性会大大降低。有时,一个经典的 if 语句序列比任何花哨的 LINQ 或其他任何东西都更合适。

【讨论】:

我会将其设置为正确答案,因为它确实提供了“调度”解决方案的选项。但我认为,正如@SomeBody 所建议的那样,我会尝试使用更简单的描述方式。【参考方案2】:

好吧,我怀疑Dictionary 在这里是否有任何帮助,但是您可以将例程稍微简化为

public bool Equals(SampleObject x, SampleObject y) 
  if (ReferenceEquals(x, y))
    return true;
  else if (x == null || y == null)
    return false;

  // From now on, both x and y are not null

  //TODO: to avoid such constructions, do not let collections be null, but empty 
  if (x.EventList == null || y.EventList == null)
    return x.EventList == y.EventList;

  // From now on, both x.EventList and y.EventList are not null

  return string.Equals(x.SomeId, y.SomeId) &&
         x.EventList.OrderBy(e => e).SequenceEquals(y.EventList.OrderBy(e => e));

【讨论】:

我喜欢这个!看起来很干净,而且不那么重复。【参考方案3】:

我认为字典在这里没有任何帮助。您可以用一个简单的表达式替换所有 if 语句:

return
    x == null && y == null ||
    x != null && y != null &&
    String.Equals(x.SomeId, y.SomeId) &&
    (x.EventsList == null && y.EventsList == null ||
     x.EventsList != null && y.EventsList != null &&
     x.EventsList.OrderBy(e => e)
        .SequenceEqual(y.EventsList.OrderBy(e => e));

请注意,由于 C# 的 short-circuit evaluation,在大多数情况下只需要对表达式进行部分计算。

【讨论】:

以上是关于如何替换字典的 IF 语句? (C#,Linq)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中使用 LINQ 过滤嵌套字典?

使用字典替换多 if 语句时计数错误

如何用 C# 中的函数语句替换 for 循环?

如何在 Linq C# 中使用嵌套字典对列表进行排序?

C# 如何在另一个 Linq 语句中的 XmlAttributeCollection 上使用 Linq?

如何在 linq 查询 c# 中的 WHERE 语句后嵌入动态 OR 条件