从接口重载泛型方法
本文关键字:泛型方法 重载 接口 | 更新日期: 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中。