我需要一种方法来摆脱使用&&操作员这么多

本文关键字:操作员 方法 一种 | 更新日期: 2023-09-27 18:11:43

我需要比较两个相同类型的对象,但是有很多prop

return string.Equals(x.Name, y.Name) && 
x.Price == y.Price && 
string.Equals(x.Species, y.Species) && 
x.AgeEnforced == y.AgeEnforced &&
x.MinimumAge == y.MinimumAge && 
string.Equals(x.WeightRange, y.WeightRange) && 
x.MinimumWeight == y.MinimumWeight

这个列表最多有14个道具

关于如何丢失&&算子的提示?

我需要一种方法来摆脱使用&&操作员这么多

如果你的类有14个属性,并且必须对它们进行比较以确保相等,那么必须在某个地方进行所有这些检查。无论你是把它们放入一个(可能是静态的)助手方法,equals方法,一个实现了IEqualityComparer的类(IMHO是最好的选择),一个扩展方法或任何你想到的方法中,你都必须一次写下所有这些检查。

你可以使用一些反射的东西(或者一个利用它的库)来遍历所有的属性,而不是自己写这些检查,但这通常不是最好的选择,因为它比较慢,而且往往会经常调用相等性检查(sort, hashset等)。所以承受痛苦,把支票写下来。

如果您认为这些检查太多,那么可能您的对象太胖并且具有太多属性。也许它需要更深层的层次结构通过使用类来代表整个事物的一部分你有一个顶级类,它有一个子类的属性然后你为每个子类单独编写比较方法顶级类只是为它的子类调用这些比较器

的回答提示我如何丢失&&运营商吗?

if (string.Equals(x.Name, y.Name) == false) return false;
if (x.Price != y.Price) return false
// ... others
return true;

这段代码一定在某个地方。如果这是这个代码存在的唯一地方,在我看来这是可以的。但是如果它存在于许多地方,那么你可以将它移动到一些辅助函数或覆盖Equals()方法在你的对象。MSDN信息。

重写Equals()示例:

public class MyObject
{
    public string Name { get; set; }
    public decimal Price { get; set; }
   
    public override bool Equals(object obj)
    {
        MyObject o = obj as MyObject;
        if (o == null)
            return false;
        if (this.Name != o.Name)
            return false;
        return true;
    }
    /// <summary>
    /// Serves as the default hash function. 
    /// </summary>
    /// <returns>
    /// A hash code for the current object.
    /// </returns>
    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}
public class Program
{
    static public void Main()
    {
        MyObject o1 = new MyObject()
        {
            Name = "a",
            Price = 1
        };
        MyObject o2 = new MyObject()
        {
            Name = "b",
            Price = 1
        };
        MyObject o3 = new MyObject()
        {
            Name = "a",
            Price = 1
        };
        Console.WriteLine("o1 == o2: {0}", o1.Equals(o2));
        Console.WriteLine("o1 == o3: {0}", o1.Equals(o3));
        Console.ReadKey();
    }
}

结果是:

1 == 2: False

0 == 0: True

对我来说,&&||已经很短了。你的问题不在于操作符本身,而在于你对14+属性进行比较的方式。

与其手工编写所有的属性比较,不如尝试自动化。

var props_string = new List<Func<MyObject, string>>();
props_string.Add(foo => foo.Name);
props_string.Add(foo => foo.Species);
//..
var props_double = new List<Func<MyObject, double>>();
props_double.Add(foo => foo.Price);
//..

现在,把它们列出来,你可以在上面运行一个循环

MyObject first = ...;
MyObject second = ...;
bool areEqual = true;
foreach(var prop in props_string)
    if(!string.Equals(prop(first), prop(second)))
        areEqual = false;
foreach(var prop in props_double)
    if(prop(first) != prop(second))
        areEqual = false;
return areEqual;

积极的一面是,即使有100个属性,一个或两个(或更多)循环将飞过它。

请注意,这段代码没有经过优化,而且相当幼稚。

更自然的做法是在第一个差异处快速退出:

foreach(var prop in props_double)
    if(prop(first) != prop(second))
        return false;

. .和/或观察那个字符串。等号和double!=double可以全部打包为同一个对象。=方法(所以你不需要单独的props_string, props_double等)

. .和/或观察到你不需要列出所有属性,你可以从Reflection中获得它们,所以你不需要在这些列表中"定义"100个属性。(但是,你通常有一些特殊的属性,你不想包括…所以你的反射方式需要一种方法来检测和跳过它们…)

. .和/或观察到如果你使用struct而不是class,你将获得完整的成员对象。等于免费比较。(但是,结构体与类在许多其他方面不同…)

. .和/或(…)

所有这些"优化"都高度依赖于你在剩下的14个以上的比较中所拥有的东西。一开始看起来很有趣也很聪明,但是属性的类型变化越多,需要进行的比较类型就越多。=可能不区分大小写?),情况就会变得更糟。有时候14倍的&&,或者14倍的if(x==y)return false真的没有那么糟糕

请不要误解我的意思:我不建议你使用我在这里展示的方式。我只是告诉你这是可能的。除非绝对相关和必要,否则不要使用它。这样做可能会花费你更多的时间

这似乎是一种正确的比较方法。

如果你的目标是能够轻松地检查两个不同的实例是否相等,你可以重写Equals()和GetHashCode()。你可以这样做:

x.Equals(y)

也可以重写operator ==。在这种情况下,你可以这样做:

x == y

查看MSDN以获取详细信息和示例。


也没有理由(除非你想使用任何额外的参数)使用

string.Equals(x.Name, y.Name) 

使用

x.Name == y.Name