C# 重载与泛型参数
我有个问题。在这个框架中,大部分是在泛型出现之前编写的,您经常会看到一个具有大量重载的函数,用于处理不同的类型 a) 这似乎还可以,因为它有助于保持每个方法的代码较小,等等。另一方面,现在使用泛型,您可以执行以下操作: b)C# 重载与泛型参数,c#,.net,vb.net,generics,overloading,C#,.net,Vb.net,Generics,Overloading,我有个问题。在这个框架中,大部分是在泛型出现之前编写的,您经常会看到一个具有大量重载的函数,用于处理不同的类型 a) 这似乎还可以,因为它有助于保持每个方法的代码较小,等等。另一方面,现在使用泛型,您可以执行以下操作: b) Parse(T数据) 然后用typeof()使用一些ifs/switch语句来推断这些类型是什么以及如何处理它们 什么是最佳实践?或者有什么想法可以帮助我在a)和b)之间进行选择?IMHO,如果你需要if/switch语句,你最好重载。泛型应该在实现不依赖于具体类型的情况
Parse(T数据)
然后用typeof()使用一些ifs/switch语句来推断这些类型是什么以及如何处理它们
什么是最佳实践?或者有什么想法可以帮助我在a)和b)之间进行选择?IMHO,如果你需要if/switch语句,你最好重载。泛型应该在实现不依赖于具体类型的情况下使用,以便仍然重用它 因此,一般来说:
- 如果每种类型都有单独的实现,则重载
- 如果可以有一个适用于所有可能类型的实现,请使用泛型
class SomeParser
{
void Parse<T>(ParseStrategy<T> parseStrategy, T data)
{
//do some prep
parseStrategy.Parse(data);
//do something with the result;
}
}
class ParseStrategy<T>
{
abstract void Parse(T data);
}
class StringParser: ParseStrategy<String>
{
override void Parse(String data)
{
//do your String parsing.
}
}
class IntParser: ParseStrategy<int>
{
override void Parse(int data)
{
//do your int parsing.
}
}
//use it like so
[Test]
public void ParseTest()
{
var someParser = new SomeParser();
someParser.Parse(new StringParser(), "WHAT WILL THIS PARSE TO");
}
class语法分析器
{
void Parse(ParseStrategy,parsetdata)
{
//做些准备
parseStrategy.Parse(数据);
//对结果做点什么;
}
}
类解析策略
{
抽象空解析(T数据);
}
类StringParser:ParseStrategy
{
重写无效解析(字符串数据)
{
//进行字符串分析。
}
}
类IntParser:ParseStrategy
{
重写无效解析(int数据)
{
//进行int解析。
}
}
//像这样使用它
[测试]
公共void ParseTest()
{
var someParser=new someParser();
Parse(新的StringParser(),“此解析将指向什么”);
}
然后你就可以通过你制定的任何策略。这将允许您跨多个类正确地隔离您的关注点,并且不会违反SRP(单一责任原则。虽然在这方面没有一刀切的规则,但当特定类型不相关时,应使用泛型。这并不是说您不能约束类型,但特定类型实际上并不重要。在这种情况下,解析方法完全依赖于(并且不同于)在这里,泛型似乎不是一个好的解决方案。代码气味 如果你有“某种If/switch”,那就是一种代码气味,它会发出多态性的尖叫。这表明泛型并不能解决这个问题。当代码不依赖于你传递给它的具体类型时,应该使用泛型
观看这段Google Tech Talks视频:“。它专门针对您正在谈论的内容。这里有一个问题-如果您需要if/switch语句来实现泛型,您可能会遇到更大的问题。在这种情况下,泛型参数很可能无法正常工作(正确)对于每种类型,只需处理一组固定的类型。在这种情况下,最好提供重载来单独处理特定类型 这有很多好处:
- 不存在误用的可能性-您的用户无法传递无效参数
- 您的API更加清晰-很明显哪些类型是合适的
- 泛型方法的使用更加复杂,对于新手用户来说也不那么明显
- 泛型的使用表明任何类型都是有效的——它们确实应该适用于每种类型
- 通用方法可能会更慢,性能更高
如果您的参数可以与任何类型一起工作,这就变得不太清楚了。在这种情况下,我经常会考虑包括重载,加上类型的通用回退方法。当您传递“预期”时,这会提供性能提升。键入该方法,但您仍然可以使用其他非预期类型。
它可能会有点模糊,如果您有其他类型的特定行为和其他类型的默认行为。当然,这是一堆简单案例的简单规则,但并不总是那么简单。如果复杂,可以考虑。要实现某些模式,如策略、访问者或其他。@John-您可以同时使用Parse(int-data)
(以及其他特定类型)和Parse(T-data)
用于其他任何内容。如果传入了某个特定的重载类型,将使用非泛型方法,否则泛型方法将推断类型参数。我同意这一点,因为通常情况下,如果向其传递不支持的类型,会发生什么情况?发生编译器错误比在运行时。糟糕……没有什么比程序员试图用整个臃肿的类层次结构替换非常普通和简单的if语句的代码更难阅读的了。@jalf糟糕……没有什么比依赖于许多选项的简单if语句反复出现的代码更难阅读的了:)这里的Polymorfism有助于维护代码:新选项只是一个新类和一个新方法,而不是对项目中的所有代码进行完全搜索!@DanibISHOP哦,我看到你刚刚发明了“反复”毫无根据。遗憾的是,这与我的评论或我评论的答案无关。答案说,如果你有某种if/开关,这是一种代码气味。它没有提到重复。@jalf我只是试图以某种讽刺的方式为general purpouses添加一些内容。这个答案使用了“气味”来自M.Fowler的概念,示例是一个Parse()函数,其中包含一个非常漂亮的“etc..”。这里没有太多的空话:数据是最好的
Parse<T>(T data)
class SomeParser
{
void Parse<T>(ParseStrategy<T> parseStrategy, T data)
{
//do some prep
parseStrategy.Parse(data);
//do something with the result;
}
}
class ParseStrategy<T>
{
abstract void Parse(T data);
}
class StringParser: ParseStrategy<String>
{
override void Parse(String data)
{
//do your String parsing.
}
}
class IntParser: ParseStrategy<int>
{
override void Parse(int data)
{
//do your int parsing.
}
}
//use it like so
[Test]
public void ParseTest()
{
var someParser = new SomeParser();
someParser.Parse(new StringParser(), "WHAT WILL THIS PARSE TO");
}