使变量最后出现在调用堆栈中

2024-01-01

我有一个包含一些字段的类。我需要按值比较此类的实例,所以我定义了GetHashCode and Equals因此。因为该类允许循环引用,所以我需要一种机制来避免无限递归(更详细的解释请参见值等于和循环引用:如何解决无限递归? https://stackoverflow.com/questions/46586427/value-equals-and-circular-references-how-to-resolve-infinite-recursion)。我通过修改我的解决了这个问题Equals方法,以便它跟踪之前完成的比较:

class Foo
{
    public string Name { get; set; }
    public Foo Reference { get; set; }

    public override int GetHashCode() { return Name.GetHashCode(); }

    static HashSet<(Foo,Foo)> checkedPairs
        = new HashSet<(Foo,Foo)>(ValuePairRefEqualityComparer<Foo>.Instance);
        // using an equality comparer that compares corresponding items for reference;
        // implementation here: https://stackoverflow.com/a/46589154/5333340

    public override bool Equals(object obj)
    {
        Foo other = obj as Foo;
        if (other == null)
            return false;

        if !(Name.Equals(other.Name))
            return false;

        if (checkedPairs.Contains((this,other)) || checkedPairs.Contains((other,this)))
            return true;

        checkedPairs.Add((this,other));

        bool refsEqual = Reference.Equals(other.Reference);
        checkedPairs.Clear();
        return refsEqual;
    }
}

想象一下 main 方法中的以下代码:

Foo foo1 = new Foo { Name = "foo" };
Foo foo2 = new Foo { Name = "foo" };
foo1.Reference = foo2;
foo2.Reference = foo1;

bool foo_equals_bar = foo1.Equals(foo2);
Console.WriteLine("foo_equals_bar = " + foo_equals_bar);

foo1.Equals(foo2)将存储(foo1,foo2) in checkedPairs在它调用之前foo2.Equals(foo1)。里面foo2.Equals(foo1)将会注意到checkedPairs包含(foo1,foo2), and true将被退回。该结果被传送到equal调用中的变量foo1.Equals(foo2), then checkedPairs被清除,并且true最终返回到main方法。

(不利用checkedPairs inside Equals,之间会有无限递归跳跃foo1.Equals(foo2) and foo2.Equals(foo1).)

这在我的单线程、非并发沙箱环境中运行得很好。然而,我只使用一个static字段为checkedPairs因为我不知道有任何其他方法可以从一次调用中转移已经收集的物品Equals到调用堆栈中的下一个。

但通过这种方法,我无法使用多线程或并发环境,其中多个Equals检查可能会并行运行或以混合顺序运行(例如,由于通过Equals作为委托并稍后而不是立即调用它)。

问题:

  1. 使用线程静态变量可以吗?恐怕不是,因为我可以想象到不同的情况Equals来自同一调用堆栈的调用仍然可以在不同的线程上执行(但我不知道)。

  2. 有没有办法制作checkedPairs“调用堆栈静态”?这样每个调用堆栈都有自己的副本checkedPairs?然后对于每个新的调用堆栈,一个新的(空)checkedPairs将在递归期间创建、填充,并在递归结束后进行垃圾收集。


感谢 jdweng 向我指出一个适用于问题中所述的特定代码的简单解决方案:

去除checkedPairs场从Foo类并替换Equals这段代码的方法:

public override bool Equals(object obj)
{
    return MyEquals(obj, new HashSet<(Foo,Foo)>(ValuePairRefEqualityComparer<Foo>.Instance));
}

private bool MyEquals(object obj, HashSet<(Foo,Foo)> checkedPairs)
{
    Foo other = obj as Foo;
    if (other == null)
        return false;

    if (!Name.Equals(other.Name))
        return false;

    if (checkedPairs.Contains((this,other)) || checkedPairs.Contains((other,this)))
        return true;

    checkedPairs.Add((this,other));

    return Reference.MyEquals(other.Reference, checkedItems);
}

然而,这种方法在一般情况下是行不通的。以这个问题中的类为例:值等于和循环引用:如何解决无限递归? https://stackoverflow.com/questions/46586427/value-equals-and-circular-references-how-to-resolve-infinite-recursion,想象我定义的MyEquals两者类似Club and Person. Since MyEquals不能从类外部调用(我希望它是私有的),仍然会有无限递归。例如。什么时候Person.MyEquals被调用,它会调用FavouriteInstitution.Equals里面,但它应该重定向到FavouriteInstitution.MyEquals不知怎的(可能已经填满了checkedPairs!)。还,Members.SetEquals(other.Members)将重定向到Person.Equals代替Person.MyEquals.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使变量最后出现在调用堆栈中 的相关文章

  • 删除文件的最后 10 个字符

    我想删除文件的最后 10 个字符 说一个字符串 hello i am a c learner 是文件内的数据 我只是希望该文件是 hello i am a 文件的最后 10 个字符 即字符串 c learner 应在文件内消除 解决方案 将
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 人脸 API DetectAsync 错误

    我想创建一个简单的程序来使用 Microsoft Azure Face API 和 Visual Studio 2015 检测人脸 遵循 https social technet microsoft com wiki contents ar
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • LINQ:使用 INNER JOIN、Group 和 SUM

    我正在尝试使用 LINQ 执行以下 SQL 最接近的是执行交叉联接和总和计算 我知道必须有更好的方法来编写它 所以我向堆栈团队寻求帮助 SELECT T1 Column1 T1 Column2 SUM T3 Column1 AS Amoun
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • C++ 中的 include 和 using 命名空间

    用于使用cout 我需要指定两者 include
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐