gpt4 book ai didi

c# - 为调用堆栈创建一个变量 last

转载 作者:行者123 更新时间:2023-11-30 12:21:12 25 4
gpt4 key购买 nike

我有一个包含一些字段的类。我需要按值比较此类的实例,因此我相应地定义了 GetHashCodeEquals。因为该类允许循环引用,所以我需要一种机制来避免无限递归(有关更详细的解释,请参见 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) 在调用 foo2.Equals(foo1 )。在 foo2.Equals(foo1) 中会注意到 checkedPairs 包含 (foo1,foo2)true将被退回。这个结果被传递给 foo1.Equals(foo2) 调用内部的 equal 变量,然后 checkedPairs 被清除,并且 true 最终返回到main方法。

(如果不在 Equals 中使用 checkedPairs,将会在 foo1.Equals(foo2)foo2 之间无限递归跳跃.Equals(foo1).)

这在我的单线程、非并发沙箱环境中工作正常。但是,我只为 checkedPairs 使用了一个 static 字段,因为我不知道还有什么其他方法可以从一次 调用中传输已收集的项目等于调用堆栈中的下一个。

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

问题:

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

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

最佳答案

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

Foo 类中删除 checkedPairs 字段并用以下代码替换 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);
}

但是,这种方法一般不会奏效。以这个问题中的类为例:Value-equals and circular references: how to resolve infinite recursion? ,想象一下我为 ClubPerson 定义了类似的 MyEquals。由于 MyEquals 不能从类外调用(我希望它是私有(private)的),所以仍然会无限递归。例如。当调用 Person.MyEquals 时,它会在内部调用 FavouriteInstitution.Equals,但它应该以某种方式重定向到 FavouriteInstitution.MyEquals(可能已经填充 checkedPairs!)。此外,Members.SetEquals(other.Members) 将重定向到 Person.Equals 而不是 Person.MyEquals

关于c# - 为调用堆栈创建一个变量 last,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46590166/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com