代码之家  ›  专栏  ›  技术社区  ›  Virus721

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

  •  -1
  • Virus721  · 技术社区  · 7 年前

    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 ,尽管 实现 IFooBar公司 ,因为它没有正式实施。

    为了允许使用 不改变 布赫 class Booh : IFooBar ,我考虑过(基于另一个问题)写一个包装器:

    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)); 布赫 我首先添加了,因为我创建了两个不同的包装器,每个包装器都有自己的地址。

    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();
        }
    }
    

    这可能导致包装对象引用被字典使用,我还没有测试。

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

    编辑:

    1 回复  |  直到 7 年前
        1
  •  0
  •   Chris F Carroll    7 年前

    是的,你所做的三种方法就是你所需要的。据称,字典主要依赖哈希代码。

    Equals(object obj) 会出问题的:它会造成 Booh 二者都 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);
        }
    

    我看不出使用struct会有什么不同。你仍然需要重写平等成员。

    我补充道

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