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

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(使用前将#替换为@)

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

  • Exit() 时是否调用基本对象析构函数?

    我意识到这个问题已经出现过几次 但我试图获得上述问题的明确答案 但我不断遇到相互矛盾的信息 我需要知道的是 当我使用 exit 时 基本类对象是否被破坏 我知道需要删除动态内存 但我的意思更像是 include
  • C# 方法重载决策不选择具体的泛型覆盖

    这个完整的 C 程序说明了这个问题 public abstract class Executor
  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • 按扩展名过滤搜索文件返回太多结果

    我正在开发一个 C 控制台应用程序 它必须管理 Windows 操作系统上的文件 我需要获取具有特定扩展名的文件名 列表 我找到了很多解决方案 最建议的是以下一种 HANDLE hFind WIN32 FIND DATA data hFin
  • 从复选框列表中选择循环生成的复选框中的一个复选框

    抱歉我的英语不好 在我的 ASP NET 网站上 我从 SQL 表导入软件列表 看起来像这样 但实际上要长得多 Microsoft Application Error Reporting br br Microsoft Applicatio
  • 传递 constexpr 对象

    我决定给予新的C 14的定义constexpr旋转并充分利用它 我决定编写一个小的编译时字符串解析器 然而 我正在努力保持我的对象constexpr将其传递给函数时 考虑以下代码 include
  • 如何将 SOLID 原则应用到现有项目中

    我对这个问题的主观性表示歉意 但我有点卡住了 我希望之前处理过这个问题的人能够提供一些指导和建议 我有 现在已经成为 一个用 C 2 0 编写的非常大的 RESTful API 项目 并且我的一些类已经变得巨大 我的主要 API 类就是一个
  • cpp.react库的C++源代码中奇怪的“->* []”表达式

    这是我在文档中找到的 C 片段cpp react 库 https github com schlangster cpp react implicit parallelism auto in D MakeVar 0 auto op1 in g
  • 语音识别编程问题入门

    所以 你们可能都看过 钢铁侠 其中托尼与一个名为贾维斯的人工智能系统进行交互 演示剪辑here http www youtube com watch v Go8zsh1Ev6Y 抱歉 这是广告 我非常熟悉 C C 和 Visual Basi
  • Eigen 和 OpenMP:由于错误共享和线程开销而没有并行化

    系统规格 Intel Xeon E7 v3 处理器 4 插槽 16 核 插槽 2 线程 核心 Eigen 系列和 C 的使用 以下是代码片段的串行实现 Eigen VectorXd get Row const int j const int
  • 什么是空终止字符串?

    它与什么不同标准 字符串 http www cplusplus com reference string string 字符串 实际上只是一个数组chars 空终止字符串是指其中包含空字符的字符串 0 标记字符串的结尾 不一定是数组的结尾
  • 模板外部链接?谁能解释一下吗?

    模板名称具有链接 3 5 非成员函数模板可以有内部链接 任何其他模板名称应具有外部链接 从具有内部链接的模板生成的实体与在其他翻译单元中生成的所有实体不同 我知道使用关键字的外部链接 extern C EX extern C templat
  • 在 C# 中为父窗体中的子窗体控件添加事件处理程序

    我有两种形式 一种是带有按钮和文本框的父表单 单击该按钮时 将打开一个对话框 该子窗体又包含一个文本框和一个按钮 现在我想要的是 每当子表单文本框中的文本更改时 父表单文本框中的文本会自动更改 为了获得这个 我所做的是 Form3 f3 n
  • 比较:接口方法、虚方法、抽象方法

    它们各自的优点和缺点是什么 接口方法 虚拟方法 抽象方法 什么时候应该选择什么 做出这一决定时应牢记哪些要点 虚拟和抽象几乎是一样的 虚方法在基类中有一个实现 可以选择重写 而抽象方法则没有 并且must在子类中被覆盖 否则它们是相同的 在
  • 使动态创建的链接标签在 Winforms 中可点击

    我正在制作一个程序 允许用户单击由动态链接标签创建的公司名称 在我想知道如何做到这一点之前 我从未在 C 中使用过链接标签 可为特定用户生成的业务数量各不相同 因此每个用户的链接标签数量并不相同 然后我想捕获业务 ID 以进行 Json 调
  • Visual Studio 2015 - Web 项目上缺少共享项目参考选项卡

    我从 MSDN 订阅升级到 Visual Studio 2015 因为我非常兴奋地阅读有关共享项目的信息 当我们想要做的只是重用代码时 不再需要在依赖项中管理 21382 个 nuget 包 所以我构建了一个测试共享项目 其中包含一些代码
  • 如何在 sql azure 上运行 aspnet_regsql? [复制]

    这个问题在这里已经有答案了 可能的重复 将 ASP NET 成员资格数据库迁移到 SQL Azure https stackoverflow com questions 10140774 migrating asp net membersh
  • 无法将字符串文字分配给装箱的 std::string 向量

    这是我的类型系统的简化版本 include
  • 为什么空循环使用如此多的处理器时间?

    如果我的代码中有一个空的 while 循环 例如 while true 它将把处理器的使用率提高到大约 25 但是 如果我执行以下操作 while true Sleep 1 它只会使用大约1 那么这是为什么呢 更新 感谢所有精彩的回复 但我
  • 我可以使用 lambda 函数或 std::function 对象来代替函数指针吗?

    我有一个需要使用的库 它定义了以下内容 typedef void CallbackFunction const int i 并且有一个注册回调的函数 如下所示 void registerCallback CallbackFunction p

随机推荐