简体   繁体   中英

C# How to avoid generic pushing <T> method into signature collision with non-generic method?

I'm running into an issue that I cannot figure out. I have an interface that provides a method signature. This method takes in a string, and returns a bool.

This interface is then implemented by an abstract class that takes a generic type T argument to define an overloaded version of the interface function. This overloaded method takes in a T and returns a bool. Likewise, the interface method is abstracted out for implementation by concrete classes rather than an abstract implementation.

I run into a problem when the concrete class feeds in a string for T because it seems to cause some sort of collision between the interface method signature and the abstract method signature. I tried looking for a solution, but my google-fu fails me.

When I compile I receive the following error messages:

Error 2 'FooBarTest1.StringFoo' does not implement inherited abstract member 'FooBarTest1.AFoo.Bar(string)' Program.cs 41 18 ConsoleApplication1

Error 3 The inherited members 'FooBarTest1.AFoo.Bar(string)' and 'FooBarTest1.AFoo.Bar(T)' have the same signature in type 'FooBarTest1.StringFoo', so they cannot be overridden ConsoleApplication1\\Program.cs 43 30 ConsoleApplication1

Is there a clean way around this besides changing one of the method names? (example code below)

namespace FooBarTest1
{
    public class Program
    {
        static void Main(string[] args)
        {
            Foo f = new Foo();
        }
    }

    public interface IFoo
    {
        bool Bar(string foo);
    }

    public abstract class AFoo<T> : IFoo
    {
        public abstract bool Bar(string foo);
        public abstract bool Bar(T foo);
    }

    public class IntFoo : AFoo<int>
    {
        public override bool Bar(string foo)
        {
            return true;
        }

        public override bool Bar(int foo)
        {
            return Bar(foo.ToString());
        }
    }

    public class StringFoo : AFoo<string>
    {
        public override bool Bar(string foo)
        {
            return true;
        }
    }
}

You will have to rename the method (or otherwise change the signature). The problem is if T is of type String , then the two Bar methods collide. In other words, when T is a string, you are no longer overloading the method - you're copying the method, which is an error.

One question to ask is, "what does the string implementation of Bar do differently than the generic implementation (especially in the case where the generic type is a string)?" If the answer is "they are different because..." , then it should make sense to change the name to reflect the different behavior.

If the implementation is the same, then the logic inside the implementation should handle that case and you would only need one method with that signature. In other words, you could keep just the implementation with a string parameter, and then examine the type of T inside the method to do something else if needed.

Otherwise, if you don't want to rename or remove one of them, you could do something like:

public abstract class AFoo<T> : IFoo
{
    // Change the signature without renaming
    public abstract bool Bar(string foo, string baz); 
    public abstract bool Bar(T foo);
}

Yes, there is a way to avoid changing the method names. Use Explicit Interface Implementation (see https://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx ) as follows:

public abstract class AFoo<T> : IFoo
{
    // Change the signature without renaming
    abstract bool IFoo.Bar(string foo); 
    public abstract bool Bar(T foo);
}

AFoo would then be used as:

AFoo<String> af = new Implementation();
//Call generic method
Console.Writeline(af.Bar("Hello world!"));
//Call interface method
Console.Writeline(((IFoo)af).Bar("Hello world!"));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM