【问题标题】:Hide a base class method in a generic derived class在泛型派生类中隐藏基类方法
【发布时间】:2023-03-28 23:47:01
【问题描述】:

我有一个这样的基类:

class FooBase
{
    public bool Do(int p) { /* Return stuff. */ }
}

还有一个像这样的子类:

class Foo<T> : FooBase
{
    private Dictionary<T, int> Dictionary;

    public bool Do(T p)
    {
        int param;
        if (!Dictionary.TryGetValue(p, out param))
            return false;
        return base.Do(param);
    }
}

如果用户创建了一个名为“fooString”的Foo&lt;string&gt;对象,那么他可以同时调用fooString.Do(5)fooString.Do("test"),但是如果他创建了一个名为“fooInt”的Foo&lt;int&gt;对象,他只能调用Do方法派生类的。不管T 是什么,我更喜欢第二个。

这两个类中的 Do 方法本质上是做同样的事情。派生类中的一个使用给定参数从Dictionary&lt;T, int&gt; 中获取一个整数,并使用它调用基类的 Do 方法。

这就是为什么我想在Foo&lt;T&gt; 中隐藏FooBase 的Do 方法。我怎样才能做到这一点或类似的东西?任何克服这一点的设计建议也很好。

【问题讨论】:

  • 你考虑过保护基类的 Do 吗?
  • @Hammerstein - 是的,但我需要公开。基类不是抽象的,Do 方法是它的主要功能,所以它必须是公共的。
  • 如果他们做同样的事情,你从隐藏基本方法中得到什么?如果调用另一个变体应该没有什么区别,因为它们做同样的事情。

标签: c# inheritance method-hiding


【解决方案1】:

但是如果他创建了一个名为“fooInt”的Foo&lt;int&gt;对象,他只能调用派生类的Do方法。

不,那不是真的。如果变量的声明类型是FooBase,它仍然会调用FooBase方法。你并没有真正阻止对FooBase.Do 的访问——你只是在隐藏它。

FooBase foo = new Foo<int>();
foo.Do(5); // This will still call FooBase.Do

完整的示例代码表明:

using System;

class FooBase
{
    public bool Do(int p) { return false; }
}

class Foo<T> : FooBase
{
    public bool Do(T p) { return true; }
}

class Test
{
    static void Main()
    {
        FooBase foo1 = new Foo<int>();
        Console.WriteLine(foo1.Do(10)); // False

        Foo<int> foo2 = new Foo<int>();
        Console.WriteLine(foo2.Do(10)); // True
    }
}

这就是为什么我想在 Foo 中隐藏 FooBase 的 Do 方法。

你需要考虑Liskov's Substitutability Principle

要么 Foo&lt;T&gt; 不应派生自 FooBase(使用组合而不是继承) FooBase.Do 不应可见(例如,使其受到保护)。

【讨论】:

  • 确实,它调用了派生的Do方法。
  • @d4wn:不,它会调用基类的 Do 方法,我敢肯定。我现在会验证它,但我真的很确定......
  • @d4wn:我已经编辑了我的答案以显示一个简短但完整的程序,证明当变量的类型为 FooBase 时,它会调用基类的 Do 方法。
  • 其实两者都是真的。对于Foo&lt;int&gt; 实例,如果变量声明为FooBase,则将调用base 方法。如果声明为Foo&lt;int&gt;,则调用派生类的方法。
  • 我不认为new 只是为了向后兼容。我通常使用它来解决 C# 中缺少结果类型协方差的问题。所以派生类对基类隐藏了一个等价的方法,但是有一个更具体的结果类型。
【解决方案2】:

您可以使用protected Do 方法构建一个抽象的基类,并重写您当前的FooBase 类以从Foo&lt;T&gt; 继承:

public abstract class FooBaseAbstract
{
    protected bool Do(int p)
    {
        return true;
    }
}

// You can use this one just as your current FooBase class
public class FooBase : Foo<int>
{
}

public class Foo<T> : FooBaseAbstract
{
    public bool Do(T p)
    {
        if (true /* some test here */)
        {
            return base.Do(4);
        }

        return false;
    }
}

(当然要改类名)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-22
    • 2012-09-08
    • 1970-01-01
    • 2016-11-15
    • 1970-01-01
    • 1970-01-01
    • 2019-03-08
    相关资源
    最近更新 更多