是否可以在 C# 的泛型方法中利用多态性?

问题描述 投票:0回答:1
string Foo(string key, string defaultValue)
{
    return Lookup(key);
}

bool Foo(string key, bool defaultValue)
{
    return bool.Parse(Lookup(key));
}

T Bar<T>(string key, T defaultValue)
{
    return Foo(key, defaultValue);
}

上面生成一个错误:无法从 'T' 转换为 'string'。据推测,这是因为编译器处理代码的顺序,但它在不等待找出泛型如何使用的情况下验证泛型似乎是违反直觉的。有没有办法解决?谢谢。

(注意:这是一个简化的示例。在实际代码中,Bar 正在做有用的事情,而不仅仅是作为多态性的毫无意义的通用包装器)

c# generics polymorphism
1个回答
0
投票

上面生成一个错误:无法从 'T' 转换为 'string'。大概这是因为编译器处理代码的顺序

不,顺序并不重要。

在 C# 中,编译器需要确保泛型类型参数可以替换为 any 兼容类型。这确保了泛型类型可以在库中分发。实际的机器代码仅由抖动生成,并且您不希望抖动给出运行时错误,您希望在编译源代码时完成所有验证。

您希望

Bar("key", 0.1d)
做什么?它显然不能工作,所以它应该生成一个编译时错误。但是让编译器检查实际的方法实现确实很困难并且可能很耗时。

因此,解决方案是显式告诉编译器哪些类型可以与泛型方法一起使用。 IE。 通用约束

void Foo(IMyInterface value) { }

void Bar<T>(T value) where T : IMyInterface
{
    Foo(value);
}

这是可行的,但应用程序有些限制。您不能像示例中那样对原始类型使用泛型限制。您也无法根据泛型类型解析方法,至少在没有运行时类型检查的情况下是这样。但是,如果这是目标,您可以在

IMyInterface
上调用虚拟方法。

因此,C# 泛型非常适合各种类型的集合,您根本不关心类型是什么。它可以用于其他用途,例如允许编译器为特定类型生成专门的代码。但如果这是最好的解决方案,您可能应该多考虑一下。我有时会看到泛型的过度使用,其中具有多态性的常规代码提供了整体更简单的解决方案。

相比之下,C++ 模板只需要使用代码实际使用的类型。但这意味着模板需要作为头文件分发。无法使用模板类型创建编译库。模板也是(无意中)图灵完备的,因此你无法知道编译是否会完成。而且模板确实往往会导致编译时间长和错误消息不佳。

如果总体目标是进行依赖于多种类型的调用,请参阅多重调度。没有对此的内置支持(除了“动态”),但您可以使用 访问者模式 作为解决方法。

© www.soinside.com 2019 - 2024. All rights reserved.