从接口重载泛型方法

本文关键字:泛型方法 重载 接口 | 更新日期: 2023-09-27 17:58:34

我有一个通用方法的接口:

interface IConverter
{
    void Convert<T>(T value);
}

我想为任何类型实现它,但我也知道对于string,方法逻辑可以简化,所以我想专门为string重载它(就像这个问题中一样):

class Converter : IConverter
{
    public void Convert<T>(T value)
    {
        Console.WriteLine("Generic Method " + value);
    }
    public void Convert(string value)
    {
        Console.WriteLine("String Method " + value);
    }
}

当我有Converter的实例并直接调用方法时,这很好。代码

var converter = new Converter();
converter.Convert("ABC");
converter.Convert(123);

输出

String Method ABC
Generic Method 123

然而,当我使用接口时(就像在任何带有DI的应用程序中一样),我不能调用string的重载。代码

var converter = (IConverter)new Converter();
converter.Convert("ABC");
converter.Convert(123);

输出:

Generic Method ABC
Generic Method 123

是否有任何方法可以在不进行类型检查的情况下完成string重载方法的调用,如

if (typeof(T) == typeof(string))
    ...

从接口重载泛型方法

否。您将converter强制转换为IConverter,因此在converter变量上只有一个可见的方法:Convert<T>(T value)

您可以通过将Convert(string)添加到接口来克服这一问题,或者根本不强制转换到接口,继续使用Converter类。只有到那时,其他方法才会可见。

有两种方法,

要么你在你的界面中包括这种方法,比如

interface IConverter
{
    void Convert<T>(T value);
    void Convert(string value);
}

将特定于string的方法创建为扩展方法

public static void Convert(this string str, string value)
{
  // code here
}

也许你的设计是颠倒的,你的接口应该是通用的:

interface IConverter<T>
{
    void Convert(T value);
}

这将允许您以特定的方式实现特定类型:

class BaseConverter<T> : IConverter<T>
{
    public void Convert(T value) 
    { /* some common way */ }
}
class StringConverter : IConverter<string>
{
    public void Convert(string value) 
    { /* strings get converted here */ }
}

您可能有一个"工厂"类,它将提供正确的转换器实例:

class ConverterFactory
{
    // this is basically "poor man's" service locator,
    // but the same idea works with DI, where you
    // would register individual comparers 
    public IConverter<T> Create<T>()
    {
         // use a Dictionary, or add that
         // typeof(T) == typeof(string) check here
    }
}

这类似于在.NET BCL中如何定义IComparer<T>,并与Comparer<T>.Default耦合。

这也是更好地使用DI的方法,因为您的IConverter<T>依赖于T,而使用单个非通用IConverter无法告诉DI要注入哪个特定实例。

可以在泛型方法中进行一些类型检查。

public void Convert<T>(T value)
{
    Console.WriteLine(typeof(T) == typeof(string) ? "String Method" : "Generic Method " + value);
}

然而,这样做忽略了通用的所有内容,不是吗?话虽如此,但不建议这样做。

无论如何,仅仅因为两个方法具有相同的名称并不意味着它们相等,因为编译器Convert(string)Convert<T>(T)是完全不同的方法。然而,接口只知道泛型方法,所以当转换到它时,根本不知道字符串方法。

正如Patrick已经提到的那样,在接口上省略强制转换或实现字符串方法。另一个也是肮脏的黑客攻击是将通用调用重定向到字符串方法:

class Converter : IConverter
{
    public void Convert<T>(T value)
    {
        if (typeof(T) == typeof(string) this.Convert((string) value);
        else Console.WriteLine("Generic Method " + value);
    }
    public void Convert(string value)
    {
        Console.WriteLine("String Method " + value);
    }
}

如果你真的非常想保持接口不变,你可以使用类型检查:

class Converter : IConverter
{
    public void Convert<T>(T value)
    {
        if (value is string)
        {
            Console.WriteLine("String Method " + (string)value);
        }
        else
        {
            Console.WriteLine("Generic Method " + value);
        }
    }
}

或者,正如其他人所说,您可以将Convert(字符串)添加到IConverter中。