为结构实现 IEquatable,并通过引用传递

Implement IEquatable for struct, and pass by reference

提问人:myavuzselim 提问时间:12/16/2022 最后编辑:myavuzselim 更新时间:12/17/2022 访问量:146

问:

是否可以从结构实现 IEquatable,但通过引用传递 compare 参数?

例:

struct BigToCopy : IEquatable<BigToCopy>
{
    int x, y, z, w, foo bar, etc;

    bool Equals(in BigToCopy other) // does not compile with 'in' parameter
    {
    }
}

它不会编译,因为当有“in”关键字时,它似乎不会实现。IEquatable<BigToCopy>

这个是可以的,但它按值复制:

struct BigToCopy : IEquatable<BigToCopy>
{
    int x, y, z, w, foo bar, etc;

    bool Equals(BigToCopy other) // does compile
    {
    }
}

IEqualityComparer据我所知,也有同样的问题。它要求参数按值传递。

编译器优化会避免复制吗,即使我们按值传递?注意:我在 Unity 上。使用 mono 和 il2cpp。

编辑:好的,让我们更具体一点。我们的代码库中有许多类是这样实现的:

struct Vertex
{
    public Point3d Position; // 3 doubles
    public Vector3d Normal; // 3 doubles
    public Vector2d UV; // 2 doubles
    public Color Color; // 4 bytes
    // possibly some other vertex data

    public override bool Equals(object obj) { ... }
    public bool Equals(in Vertex vertex) { ... }
}

有多个这样的类。它们以 HashSet、Dictionaries 等形式被放入集合中。在某些情况下,它们还通过明确的调用来进行比较。这些对象可以创建数千甚至数百万个,并以某种方式进行处理。它们通常位于热代码路径中。Equals

最近,我发现使用这些对象进行字典查找会导致对象分配。原因是:这些对象不实现 IEquatable。因此,字典会改为调用重载,这会导致装箱(= 内存分配)。Equals(object obj)

我现在正在通过实现 IEquatable 接口并删除“in”关键字来修复这些类。但是有一些现有的代码直接调用这些 Equals 方法,我不确定我是否严重影响了性能。我可以尝试,但是我以这种方式修复了很多类,所以检查的工作量太大了。 相反,我添加了另一种方法:

public bool EqualsPassByRef(in Vertex vertex) { ... }

并替换 by 的显式调用。EqualsEqualsPassByRef

这种方式工作正常。与以前相比,性能会更好。我只是想知道:也许有一种方法可以让 C# 从字典中调用“in”版本。这样就不需要“EqualsPassByRef”版本了,使代码看起来更好(在字典查找中也可能更快)。从答案中,我得出结论,这是不可能的。好吧,这还是可以的。

顺便说一句:我是 C# 的新手。我来自一个 C++ 世界。

C# 按引用传递 IEquatable

评论

5赞 Ralf 12/16/2022
对不起,没有回答,而是问了一个反问题。如果它是“BigToCopy”,那么首先使用结构体是一个明智的决定吗?是否要求将其设置为结构?
5赞 Dmitry Bychenko 12/16/2022
从技术上讲,您可以尝试声明为 ,但这种做事方式会带来许多限制。你为什么不声明为?BigToCopyref structBigToCopyclass
1赞 BurnsBA 12/16/2022
你想在这里解决什么问题?字典键查找等将使用标准等于方法。那么,您是否有自定义代码尝试通过引用使用值类型进行调用?如果是这样,为什么不能声明第二种方法呢?EqualsEqualspublic bool /* IEquatable*/ Equals(BigToCopy other) { ... } public bool /* other */ Equals(ref BigToCopy other) { ... }
0赞 myavuzselim 12/17/2022
我们的代码库中有多个结构实例可能是“BitToCopy”。不过,我可能会夸大其词。可能的示例:包含 16 个双精度值的矩阵。包含 3 个顶点位置双精度、3 个顶点法线、4 个颜色字节、可能还有一些额外的顶点数据等的顶点数据的顶点数据。可以创建这些数据的许多实例(例如数百万个)。它们被用作哈希集、字典等中的键。还有一些代码可以显式比较这些对象之间的相等性。我正在审查和修复他们的 Equals 实现。
1赞 BurnsBA 12/17/2022
听起来你回答了你的问题。您希望实现以提高值类型的性能,如下所示:learn.microsoft.com/en-us/dotnet/api/... .您无法更改字典实现,但如果您真的想更改它检查相等的方式,则可以创建自己的自定义字典类。但是,您可能应该通过引用传递值类型来修复代码,使其不调用相等性检查方法。IEquatable

答: 暂无答案