Hide a base class method in a generic derived clas

2020-04-08 14:44发布

问题:

I have a base class like this:

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

And a child class like this:

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

If the user creates a Foo<string> object called "fooString", then he can call both fooString.Do(5) and fooString.Do("test") but if he creates a Foo<int> object called "fooInt", he can only call the Do method of the derived class. I prefer the second no matter what the T is.

The Do methods in both of these classes essentially do the same thing. The one in the derived class gets an integer from a Dictionary<T, int> using the given parameter and calls the Do method of the base class using it.

That's why I want to hide the Do method of the FooBase in Foo<T>. How can I achieve this or something similar? Any design advice to overcome this would also be nice.

回答1:

but if he creates a Foo<int> object called "fooInt", he can only call the Do method of the derived class.

No, that's not true. If the declared type of the variable is FooBase, it will still call the FooBase method. You're not really preventing access to FooBase.Do - you're just hiding it.

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

Full sample code to show that:

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
    }
}

That's why I want to hide the Do method of the FooBase in Foo.

You need to think about Liskov's Substitutability Principle.

Either Foo<T> shouldn't derive from FooBase (use composition instead of inheritance) or FooBase.Do shouldn't be visible (e.g. make it protected).



回答2:

You could build a base class that is abstract with a protected Do method, and rewrite your current FooBase class to inherit from Foo<T>:

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

(of course change the class names)