'Abstract generic overlaps with non generic of base class

I have the following base classes

The non-generic:

public abstract class Foo
{
    public abstract bool DoMagic(string str1, string str2);
}

The generic class, inheriting from the non-generic:

public abstract class Foo<T> : Foo
{
    public abstract bool DoMagic(T t1, T t2);
}

Now I want to implement this class

public class FooNumeric : Foo<int>
{
    public override bool DoMagic(string str1, string str2) => true;
    public override bool DoMagic(int int1, int int2) => true;
}

Everything works as excepted as you can see here:

https://dotnetfiddle.net/kWQUl9

Now I would like to not use int as the generic constraint but instead string.

public class FooString : Foo<string>
{
    public override bool DoMagic(string str1, string str2) => true;
    //public override bool DoMagic(string int1, string int2) => true;
}

But I can't seem to satisfy the compiler and I keep getting the error

'FooString' does not implement inherited abstract member 'Foo.DoMagic(string, string)'

https://dotnetfiddle.net/rfncTE

I have tried a couple of things, but to no success.

Is this possible?

Solutions I know that could fix this

  1. Use the non-generic class on FooString

    Can't do this because Foo<T> contains many more generic methods and I have this overlapping on only one occasion.

  2. Rename the method

    if possible I would like to stick to the names.



Solution 1:[1]

In my opinion, the method that receives generic type parameters (DoMagic(T, T)) should have a more general name than a corresponding method that receives concrete types (e.g. DoMagic(string, string)). It is not just that you have a syntactic collision, but you also have a semantical collision in a sense that general and particular concepts share the same name.

Here is one naming scheme where a more concrete method (receiving string) has a more specific name, telling that it will do stuff with the strings.

public class Foo<T>
{
    public bool DoMagic(T a, T b) { ... }
}

public class FooString : Foo<string>
{
    public bool DoMagicWith(string a, string b) { ... }
}

Another naming scheme is to note that general method (receiving the generic type parameter) is performing an operation with a wider definition than any method with concrete parameter types:

public class Foo<T>
{
    public bool DoAnyMagic(T a, T b) { ... }
}

public class FooString : Foo<string>
{
    public bool DoMagic(string a, string b) { ... }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Zoran Horvat