Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 4.0 这是预期的C#4.0元组相等行为吗?_.net 4.0_C# 4.0_Tuples - Fatal编程技术网

.net 4.0 这是预期的C#4.0元组相等行为吗?

.net 4.0 这是预期的C#4.0元组相等行为吗?,.net-4.0,c#-4.0,tuples,.net 4.0,C# 4.0,Tuples,我看到在.NET4.0的两个新元组实例之间使用.Equals和==的行为有所不同。如果我在元组中的对象上重写了Equals,并在元组中调用了.Equals,那么将调用Equals的重写。如果我在元组上使用==,则不会调用等于的覆盖。这是故意的吗?有意义吗 编辑:从答案和评论中我可以看出我不清楚。我知道Tuple是一种引用类型,对于引用类型==将检查标识(ReferenceEquals)。但是,元组是否应该覆盖==以检查它包含的对象的相等性?为了一致性,可能不是 例如,如果我有一个简单的对象 pu

我看到在.NET4.0的两个新元组实例之间使用.Equals和==的行为有所不同。如果我在元组中的对象上重写了Equals,并在元组中调用了.Equals,那么将调用Equals的重写。如果我在元组上使用==,则不会调用等于的覆盖。这是故意的吗?有意义吗

编辑:从答案和评论中我可以看出我不清楚。我知道Tuple是一种引用类型,对于引用类型==将检查标识(ReferenceEquals)。但是,元组是否应该覆盖==以检查它包含的对象的相等性?为了一致性,可能不是

例如,如果我有一个简单的对象

public class NameAndNumber
{
    public int Number { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        if (obj is NameAndNumber)
        {
            NameAndNumber other = (NameAndNumber)obj;
            return Number == other.Number && Name == other.Name;
        }

        return false;
    }
}
然后我做了这样的事情:

Tuple<NameAndNumber, NameAndNumber> left = new Tuple<NameAndNumber, NameAndNumber>(
      new NameAndNumber { Name = "one", Number = 1 }, 
      new NameAndNumber { Name = "two", Number = 2 });
Tuple<NameAndNumber, NameAndNumber> right = new Tuple<NameAndNumber, NameAndNumber>(
      new NameAndNumber { Name = "one", Number = 1 }, 
      new NameAndNumber { Name = "two", Number = 2 });
bool operatorResult = left == right;
bool equalsResult = left.Equals(right);
Console.Out.WriteLine("operatorResult = {0}  equalsResult = {1}", 
        operatorResult, equalsResult);
Tuple left=新元组(
新名称和编号{Name=“one”,编号=1},
新名称和编号{Name=“two”,编号=2});
元组右=新元组(
新名称和编号{Name=“one”,编号=1},
新名称和编号{Name=“two”,编号=2});
布尔运算符result=左==右;
布尔相等结果=左。相等(右);
Console.Out.WriteLine(“operatorResult={0}equalsResult={1}”,
运算符结果、相等结果);
我得到运算符result=false等于result=true

我应该期待吗

我知道NameAndNumber上Equals的实现并不“正确”,它只是简化的示例代码


我也尝试过实现IEquatable,==,!=,和GetHashCode。相同的结果。

对于引用类型:==执行标识比较,即,只有当两个引用指向同一对象时,才会返回true。虽然Equals()方法需要执行值比较,也就是说,如果引用指向等效的对象,它将返回true


对于==未被重载的引用类型,它会比较两个引用是否引用同一个对象。默认情况下,运算符==测试引用是否相等,因此Yes您看到的结果是预期的

见:

在C#中,有两种不同的类型 平等的定义:参考平等(也包括 被称为身份)和价值平等。 价值平等是普遍存在的问题 理解平等的含义:它 表示两个对象包含 相同的值。例如,两个整数 如果值为2,则具有值 平等。参考平等手段 没有两个对象可供选择 比较一下


默认情况下,
==
(在类上)表示引用相等;i、 e.它们是否为同一实例;object.ReferenceEquals(x,y)将返回什么

您可以提供自己的==/!=运算符以获得预期的行为-当您重写
Equals
时,也必须重写
GetHashCode
(否则您会中断作为键的使用):


您看到的结果来自a,元组现在在F和C之间共享。主要的一点是,所有元组实际上都是作为引用类型实现的,这一点并不明显


元组是否应该执行深度或浅层相等性检查的决定被移动到两个接口:
IStructuralComparable
IStructuralEquatable
。请注意,这两个函数现在也由Array类实现。

除了string,它是magic。所以我想我在寻找更多的魔法。您是否希望一组值类型来执行值检查?它没有。没有魔法-它只是过载==/!=经营者;您可以在reflector中将其视为op_等式和op_不等式(在System.String上)。然而,像
int
/
float
(在规范中定义)和
Nullable
(使用“提升”运算符)这样的东西是有魔力的。我不确定我是否完全理解您的注释,示例代码中的元组是一种引用类型,不是吗。@Marc Gravell。抱歉,魔术评论不清楚。我知道它是如何工作的,谢谢你的澄清。字符串上的重写使它的行为不同于大多数其他BCL对象,这使我有时认为==将神奇地作用于其他引用类型。这当然会让我问一些关于元组的问题,这些问题我应该自己解决。@J.W.对不起,今天早上我真的不太清楚。我完全是时差,不应该问问题。我真的想指出一些人所说的话。该==将进行标识比较,除非您重写它。说魔术是一个糟糕的词语选择,并增加了混乱。这并不是说你的回答不适用于我指出的情况。谢谢,我知道。正如我提到的,我展示了一个简化的实现,并将GetHashCode留给了一个较小的示例。但这不会改变元组的工作方式,我不能将它们添加到元组中。我可以从元组派生并添加它们。如果多态性是一个问题,那么让==使用
.Equals
-除此之外。。。这就是
=
的工作原理。如果你不让它过载,它就不会这样工作@马克·格雷威尔。我想问题的核心在于.NET4.0中内置的Tuple类是否应该这样做。它是否应该像标准引用类型或委托相等性检查一样检查它所包含的对象?它只是一个容器,所以我们应该关心两个容器是否相同,还是应该检查容器内容。这不是我的元组实现,而是内置的.NET4。以前使用Tuple或Pair实现的第三方库将覆盖==检查所包含对象的相等性。啊,直到最近的一次编辑,这个问题才清楚地表明您在谈论.NET 4.0s的
Tuple
类型。公平地说,我错过了标签-p@Marc格拉威尔。很抱歉。我试着让它更清楚,并且学会了不要依赖标签。谢谢你的回答和评论。我本该预料到这种行为。我将用.NET替换我们自己编写的项目3.5元组实现
public static bool operator == (NameAndNumber x, NameAndNumber y) {
    if (x == null && y == null) return true;
    if (x == null || y == null) return false;
    return x.Number == y.Number && x.Name == y.Name;
    // or if polymorphism is important: return x.Equals(y);
}
public static bool operator !=(NameAndNumber x, NameAndNumber y) {
    return !(x == y); // lazy but works
}
public override int GetHashCode() {
    return (Name == null ? 0 : Name.GetHashCode()) +
        17 * Number.GetHashCode();
}