C# 删除具有相同值但不同标识的列表项,有效,但为什么?

问题描述 投票:0回答:2

我试图编写一个代码来删除一些列表项,但后来我意识到,我的代码不应该工作,但可以工作。

我将在本文档底部解释为什么我认为我的代码“不应该工作”,但让我先解释一下场景本身。

我的代码的基本概念

当给定路径时,对路径的每个节点执行一些拟合逻辑。

详情如下:

  1. 每个节点都可能有从前一个节点的传入方向和/或到下一个节点的传出方向,除非路径是单节点的。
  2. 假设传入/传出方向始终水平或垂直对齐。
    • 换句话说,路径只能向 4 个方向移动,x 和 y
  3. 我想在未使用的一侧盖上盖子。
    • 例如,如果传入方向是向左,传出方向是向右,我想在顶部和底部放置一个盖子。

测试不应该工作但有效的代码:

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# list identity equality
2个回答
2
投票

或者,C# 相等运算符的基本行为是否基于对象的值...?

未为

==
定义相等运算符 (
Dir
)。

但是

List<T>
使用了
Equals()
方法来删除(),这确实执行了成员方面的比较。


0
投票

让我们按照文档进行操作,从

List.Remove()
开始。我们在备注部分摘录如下:

如果类型

T
实现了IEquatable通用接口,则相等比较器是该接口的Equals方法;否则,默认的相等比较器是 Object.Equals。

我在

IEquatable<T>
结构体上没有看到任何
Dir
,所以现在让我们看看
Object.Equals
方法
。现在文档的备注部分为我们提供了以下信息:

当前实例与obj参数的比较类型取决于当前实例是引用类型还是值类型。

如果当前实例是值类型,则 Equals(Object) 方法将测试值是否相等。价值平等意味着以下内容:

  • 这两个对象属于同一类型...
  • 两个对象的公有字段和私有字段的值相等。
© www.soinside.com 2019 - 2024. All rights reserved.