C# Template method override in concrete class from abstract base class

I have the following code which has a Base class containing an abstract template method, which in the derived classes is overridden using concrete types.

class MyObj
{
   private string name;
   public string Name { get; set; }
};

class MyObj2
{
  private string value
  public string Value { get; set; }
}

abstract class Base
{
  public abstract string toString<T>(T t);
  public void doSomething<T>(T t)
  {
    string myValue = toString<T)(t);
    ...
  }
};

class MyClass : Base
{
  public override string toString<MyObj>(MyObj o)
  {
     return o.Name;
  }
}

class MyClass2 : Base
{
  public override string toString<MyObj2>(MyObj2 o)
  {
     return o.Value;
  }
}

But the compiler doesn't like the implementations of toString() in MyClass or MyClass2, giving an error message along the lines of:

'MyObj' does not contain a definition for 'Name' and no extension method 'MyObj' accepting a first argument of type 'MyObj' could be found (are you missing a using directive or an assembly reference?)

Jon Skeet
people
quotationmark

You appear to be trying to provide an implementation for one specific type argument. You can't do that, and it doesn't make sense - it's not clear what would happen if the caller passed in a different type argument, e.g.

Base b = new MyClass2();
b.doSomething<int>(10);

(At the moment, your MyObj and MyObj2 in the methods are being treated as type parameters rather than as the types themselves, which is why the compiler doesn't know anything about your Name or Value properties.)

It sounds like really it should be the class which is generic:

abstract class Base<T>
{
  public abstract string ToString(T t);
  public void DoSomething(T t)
  {
    string myValue = ToString(t);
    ...
  }
}

class MyClass : Base<MyObj>
{
  public override string ToString(MyObj o)
  {
     return o.Name;
  }
}

class MyClass2 : Base<MyObj2>
{
  public override string ToString(MyObj2 o)
  {
     return o.Value;
  }
}

At this point, the previously-problematic code wouldn't work, because you'd to use Base<MyObj2> as the variable type instead of just Base, and you could only pass a MyObj to DoSomething.

(You might also want to consider making the ToString method protected instead of public. That's more common for the template method pattern, although certainly not required.)

people

See more on this question at Stackoverflow