当类实现所有接口但不声明接口时,使类适应接口



让以下接口:

interface IFoo
{
void Foo();
}
interface IBar
{
void Bar();
}
interface IFooBar : IFoo, IBar
{
// No extra required feature.
}

和类:

class Booh : IFoo, IBar
{
public void Foo() { }
public void Bar() { }
}

我不能使用Booh作为IFooBar,尽管Booh实现了IFooBar要求的一切,因为它没有正式实现它。

为了允许使用Booh作为IFooBar而不将Booh更改为class Booh : IFooBar,我想过(基于另一个SO问题(编写包装器:

class FooBar<T> : IFooBar where T : IFoo, IBar
{
public T Value { get; private set; }
public FooBar(T value)
{
Value = value;
}
public void Foo() { Value.Foo(); }
public void Bar() { Value.Bar(); }
}

问题是我可以按原样!

例如,如果我将此包装类用作字典键,它将使用包装器的引用而不是包装对象的引用。

如果我这样做:someDictionary.Add(new FooBar<Booh>(someBooh), whatever);然后someDictionary.Remove<Booh>(new FooBar(someBooh));它不会删除我首先添加的Booh,因为我创建了两个不同的包装器,每个包装器都有自己的地址。

为了解决这个问题,我已经覆盖/实现了一些用于相等性检查和哈希代码的方法:

class FooBar<T> : IFooBar where T : IFoo, IBar
{
// Same as above...
public bool Equals(FooBar<T> other)
{
return Value.Equals(other.Value);
}
public override bool Equals(object obj)
{
var cast = obj as FooBar<T>;
if (null != obj && null == cast || obj == null)
{
return false;
}
return Value.Equals(cast.Value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
}

据说这会导致字典使用包装的对象引用,我还没有测试过。

所以,我的问题是:我是否需要覆盖和/或实现其他方法才能涵盖大多数(如果不是全部(用例?我希望该包装器的行为就像是被包装的对象本身,而不是另一个对象。谢谢!

编辑:也许我可以把它变成一个结构,并依靠自动装箱将包装器结构包装成一个对象,该对象将其哈希代码和相等性检查方法委托给结构,从而使用包装的对象引用?

是的,您所做的 3 种方法就是您所需要的。据称,字典主要依赖于哈希码。

但是,您在Equals(object obj)中的转换会出错:它会将Booh转换为 null。您想测试/投射FooBar<T>和普通T

JetBrains Rider或多或少提供:

bool Equals(FooBar<T> other)
{
return EqualityComparer<T>.Default.Equals(Value, other.Value);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj is T) return Value.Equals(obj);
if (obj.GetType() != this.GetType()) return false;
return Equals((FooBar<T>) obj);
}
public override int GetHashCode()
{
return EqualityComparer<T>.Default.GetHashCode(Value);
}

通过这些测试:

[Fact]
public void CanUseInDict()
{
var foobar= new Booh();
IFooBar[] foobars= new IFooBar[]{ foobar.AsIFooBar() };
Dictionary<IFooBar,string> ifoobars= new Dictionary<IFooBar, string>()
{
{ foobar.AsIFooBar(), foobar.GetType().Name}
};
Assert.Equal( foobar.GetHashCode(),  new FooBar<Booh>( foobar ).GetHashCode());
Assert.True( foobar.AsIFooBar().Equals( new FooBar<Booh>( foobar ) )  , "Equals FooBar<Booh>");
Assert.True( ifoobars.ContainsKey( new FooBar<Booh>(foobar) ), "ContainsKey");            
ifoobars.Remove(foobar.AsIFooBar());
Assert.Empty(ifoobars);
}

我不太看出使用结构体会有很大的不同。您仍然必须以相同的方式覆盖平等成员。

我添加了

static class BoohFooBarExt
{
public static IFooBar AsIFooBar<T>(this T value ) where T:IFoo, IBar => new FooBar<T>(value);
}

最新更新