我试图编写一个代码来删除一些列表项,但后来我意识到,我的代码不应该工作,但可以工作。
我将在本文档底部解释为什么我认为我的代码“不应该工作”,但让我先解释一下场景本身。
我的代码的基本概念
当给定路径时,对路径的每个节点执行一些拟合逻辑。
详情如下:
测试不应该工作但有效的代码:
using System;
using System.Collections.Generic;
struct Dir //mock-up object
{
public int fooboo; //dummy value to be printed, to distinguish each objects
public Dir(int val) => fooboo = val;
//these are "Dir a"
public static readonly Dir forward = new Dir(1);
public static readonly Dir back = new Dir(2);
public static readonly Dir left = new Dir(3);
public static readonly Dir right = new Dir(4);
public override string ToString() => fooboo.ToString();
}
public class HelloWorld
{
public static void Main(string[] args)
{
//for filter
//these items are "Dir b"
List<Dir> sides = new List<Dir>{ Dir.forward, Dir.back, Dir.left, Dir.right };
//assume that the previous node is at the front of this node, and the next is at the back
//These two are "Dir c"
var incoming = Dir.forward;
var outgoing = Dir.back;
//filter them out from the list, so that only the 'unused sides' are left
sides.Remove(incoming); //in real scenario, it must be decorated with: if(incoming != null)
sides.Remove(outgoing); //the same as above
//testing if the filter really worked
foreach (var side in sides)
Console.Write(side);
}
}
为什么我认为该代码不应该工作?
虽然我从结构中获取相同的公共成员,但它是“struct”,这意味着我正在获取该对象的复制版本,但没有获取引用。
为了便于区分,我们将 Dir 的原始静态成员称为“Dir a”,复制版本为“Dir b”和“Dir c”。我会将这些名称留在评论中以及代码中。
从身份角度来看,“Dir b”不是“Dir a”,当然也不是“Dir c”,因为它们都是不同的实例。
那么,
List.Remove(T)
不是应该认为“Dir c”不是“Dir b”吗?
或者,C# 相等运算符的基本行为是否基于对象的值,而不是它们的标识?
或者,C# 相等运算符的基本行为是否基于对象的值...?
未为
==
定义相等运算符 (Dir
)。
但是
List<T>
使用了 Equals()
方法来删除(),这确实执行了成员方面的比较。
List.Remove()
开始。我们在备注部分摘录如下:
如果类型
实现了IEquatable通用接口,则相等比较器是该接口的Equals方法;否则,默认的相等比较器是 Object.Equals。T
我在
IEquatable<T>
结构体上没有看到任何 Dir
,所以现在让我们看看 Object.Equals
方法。现在文档的备注部分为我们提供了以下信息:
当前实例与obj参数的比较类型取决于当前实例是引用类型还是值类型。
如果当前实例是值类型,则 Equals(Object) 方法将测试值是否相等。价值平等意味着以下内容:
- 这两个对象属于同一类型...
- 两个对象的公有字段和私有字段的值相等。