适配器/包装器和相同的引用

时间:2016-05-05 15:26:17

标签: c# .net adapter

我想为另一种类型创建一个包装类。这种方法很好,直到需要(引用)-equal对象需要(引用)-equal包装器。

一个例子:

public interface ITest<T>
{
    T GetInstance(bool createNew);
}

public class Test : ITest<Test>
{
    private static Test instance;

    public Test GetInstance(bool createNew)
    {
        if (instance == null || createNew)
        {
            instance = new Test();
        }
        return instance;
    }
}


public class TestWrapper : ITest<TestWrapper>
{
    private readonly Test wrapped;
    public TestWrapper(Test wrapped)
    {
        this.wrapped = wrapped;
    }

    public TestWrapper GetInstance(bool createNew)
    {
        return new TestWrapper(wrapped.GetInstance(createNew));
    }
}
只要参数Test.GetInstancecreateNew

false将始终返回相同的实例。 相比之下TestWrapper.GetInstance总是返回一个新实例。

由于我希望能够用Test替换TestWrapper,因此我搜索一个解决方案,以便最后,如果Test返回一个新实例,则包装器仅返回一个新实例。但是,TestWrapper应该不了解Test的内部。

测试代码是

private static void RunTest<T>(ITest<T> cls)
{
    var i1 = (ITest<T>)cls.GetInstance(false);
    var i2 = (ITest<T>)cls.GetInstance(false);
    var i3 = (ITest<T>)cls.GetInstance(true);

    var dic = new Dictionary<ITest<T>, bool>();
    if (!dic.ContainsKey(i1)) dic.Add(i1, false); else dic[i1] = true;
    if (!dic.ContainsKey(i2)) dic.Add(i2, false); else dic[i2] = true;
    if (!dic.ContainsKey(i3)) dic.Add(i3, false); else dic[i3] = true;

    Console.WriteLine(string.Join(", ", dic.Select(a => a.Value.ToString())));
}

期望的结果是

True, False

如果将new Test()传递给该方法,那就是你得到的。 如果您通过new TestWrapper(new Test()),则会获得

False, False, False

有一个基于简单缓存(Dictionary<Test, TestWrapper>)的解决方案 - 但有了这个,我会在内存中保留许多实例而不再使用它们(并且GC无法收集这些实例,因为有一个参考他们)。

我稍微使用了WeakReferences,但我找不到可以用来存储WeakReference的密钥 - 因此我必须遍历缓存列表并搜索正确的实例很慢。此外,我要为每个成员(使用它自己的缓存)实现这个解决方案,这似乎不是一个很好的解决方案......

我希望我已经充分解释了我的问题;)所以,我的问题是:

  • 是否有办法欺骗object.ReferenceEquals (这个问题没有收获)
  • 我可以使用什么(作为缓存的键)作为对象实例的标识符(所以我可以使用WeakReference
  • 有没有更好的方法来实现一个真正的适配器(我可以用适配器替换适配器而不会让人头疼)

我无法访问Test类,只能访问使用它的代码(只要它实现了接口,我就可以传递任意实例)

1 个答案:

答案 0 :(得分:1)

不,你不能作弊object.ReferenceEquals()。但是,object.ReferenceEquals()是故意使用的很少,通常情况下,事情确实需要引用相等。

  

运行时需要它才能使事情正确。例如。如果实例用作Dictionary<>

中的键

实际上,运行时通常使用单个对象的.GetHashCode().Equals()行为,但恰好如果您没有在类中覆盖该行为,则基数{{1默认情况下,这些方法的实现依赖于对象引用。

因此,如果您能够更改System.Object类和Test类的代码,则可以在这些类中覆盖这些相等方法,以确保它们将等效对象识别为相等。

另一种(通常更好的)方法是创建一个TestWrapper实现,以便在您的特定用例中使用。您在IEqualityComparer<>中提到了密钥:您可以在创建字典时为字典提供Dictionary<>实例,以便以完全符合您需要的方式测试它。

IEqualityComparer<>