1

I have an abstract class ClassA, with an abstract method that takes a paramter of type ClassB. Several classes derive from it. Now I add another project, which has similar functionality, but needs a slightly different base ClassA, to derive its several classes from. The main difference: The new base class, ClassC, shouldn't ClassB as argument, but another one, that's derived from B, ClassD. ClassC should then be used as base by several classes again.

Is this possible? This is more of a question out of curiousity. I know it is possible with generics, by doing this:

public abstract void Method1<T>(T parameter) where T : ClassB;
...
public override void Method1<ClassB>(ClassB parameter) {

Is it possible without generics? And is there any dowside to them, aside from having to type the type twice?

abstract class ClassA
{
    public abstract void Method1(ClassB parameter);
}

class DerivingClasses1 : ClassA
{
    public override void Method1(ClassB parameter)
    {
        // do something
    }
}

// -------

abstract class ClassC : ClassA
{
    // This would have to override Method1 of ClassA somehow,
    // instead of overloading it.
    public abstract void Method1(ClassD parameter);
}

class DerivingClasses2 : ClassA
{
    public override void Method1(ClassD parameter)
    {
        // do something
    }
}

// -------

class ClassB
{
}

class ClassD : ClassB
{
}
Mars
  • 912
  • 1
  • 10
  • 21
  • Though tightening a parameter in a deriving class is not a good idea even if can be done, imagine doing a virtual call on a ClassC (typed as ClassA) instance giving it a ClassB (which is abseloutely valid). That could easily break the interface – Yet Another Geek May 02 '12 at 19:07

3 Answers3

4

In my opinion, the best approach would be to override the base class method with a sealed implementation that invokes the overload with the new parameter type, thereby insulating the user from the type conversion.

abstract class ClassC : ClassA
{
    public override sealed void Method1(ClassB parameter)
    {
        this.Method1(parameter as ClassD);
    }

    public abstract void Method1(ClassD parameter);
}

Edit: If used in production, you should perform proper type checking in order to avoid getting unexpected nulls:

abstract class ClassC : ClassA
{
    public override sealed void Method1(ClassB parameter)
    {
        if (!(parameter is ClassD))
            throw new ArgumentException(
                "Parameter must be of type ClassD.", "parameter");

        this.Method1((ClassD)parameter);
    }

    public abstract void Method1(ClassD parameter);
}
Douglas
  • 53,759
  • 13
  • 140
  • 188
  • I've been thinking about this as well, it sounds reasonable, and looks okay. I think I'll go with this. Thank you. – Mars May 02 '12 at 20:21
  • Casting twice is not necessary. If `parameter is ClassD` **`classD`** is added the first time, then `classD` can be used as a parameter later ([docs](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/is)). Additionally, `nameof(parameter)` should be used in the error output ([explanation](https://stackoverflow.com/a/31695982/16632604)). – Flimtix Mar 16 '22 at 14:56
  • @Nanoserver: Valid points, but this answer was written ten years ago, before either of those features existed. `nameof` was introduced with C# 6.0 in 2015, and `is` [type testing with pattern matching](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#type-testing-with-pattern-matching) with C# 7.0 in 2017 – Douglas Mar 16 '22 at 20:40
1

Just implement both methords in ClassC.

neohope
  • 11
  • 1
0

Override abstract method with another one, having different parameters

This is not really possible, however you could use a common interface:

interface IMyType {}

class MyTypeBase 
{
  public abstract void Method1(IMyType parameter); 
}
Chris Gessler
  • 22,727
  • 7
  • 57
  • 83