为什么此程序会输出Generic Value
而不是Hello world!
:
using System;
class Example
{
public static void Print<T>(T value)
{
Console.WriteLine("Generic Value");
}
public static void Print(string value)
{
Console.WriteLine(value);
}
public static void GenericFunc<T>(T value)
{
Print(value);
}
static void Main()
{
GenericFunc("Hello world!");
}
}
泛型方法参数如何在C#的引擎下翻译?
答案 0 :(得分:14)
重载分辨率仅在编译时完成。
由于GenericFunc<T>
在编译时不知道T
是string
还是其他内容,因此它只能使用Print<T>(T value)
“重载”。< / p>
使用dynamic
,您可以将其更改为动态调度,并获得您期望的行为:
Print((dynamic)value);
这使得重载解析在运行时发生,实际运行时类型为value
。
答案 1 :(得分:1)
另一个答案解释了泛型绑定的方式(编译时)。但它并没有回答OOP,良好实践,或者只是为什么你不应该首先编写这些代码。
<强> OOP 强>
OOP中的第一个O表示对象,没有静态方法。
责任
让我们考虑该方法的通用versin作为负责打印一组不同可能类型的方法。 String
类型是集合的一部分。因此,它应该由您的Print
函数的通用版本管理。
public static void Print<T>(T value)
{
Console.WriteLine(value.ToString());
}
然后你遇到了ref类型的无效问题。
public static void Print<T>(T value) where T : class
{
if (value != null)
{
Console.WriteLine(value.ToString());
}
}
public static void GenericFunc<T>(T value) where T : class
{
Print(value);
}
对于那些知道为什么你不应该使用动态的人,除非在某些情况下(see my anwer on that)。
更干净的OOP解决方案
现在假设您有不同的对象要打印。每个对象都应该负责知道如何显示它。首先,因为它不会泄漏内部数据到外部世界,从而简化了数据的封装。其次,因为你在内部数据和打印功能之间有内在的耦合,所以两者都应该位于同一个地方:在课堂内。这是ToString
功能的目的。
让我们走一些......
现在,我们可以想象它不是打印功能,而是其他东西。
我们得到了一个类的层次结构,在同一个函数上有重载(让它称之为Foo
)以及这些类的实例集合,你必须为它们调用函数Foo
。然后让所有这些类实现IFooCallable
接口:
public interface IFooCallable
{
void Foo();
}
稍微复杂......
好的,但是想象一下,没有通用的方法来处理所有这些类的实例,因为它们有很大不同。
让我们拨打Visitor pattern。当您想要分析某个对象树时,每个节点都非常不同(例如AST),这是常用的。 它是一种已知的模式,可以轻松与您的团队分享知识渊博的信息。
你有访客:
public class Visitor : IVisitor
{
public void Visit(Foo foo)
{
// do something with foo
}
public void Visit(Bar bar)
{
// do something with bar
}
}
和可访问
public class Foo : IVisitable
{
public void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
此外,这种模式是可重用的(如果需要,可以编写几种IVisitor实现)。
我不买dynamic
的东西。特别是当有更清洁,更快的替代品时。如果动态如此之大,为什么不写这个;)
public static void Print(dynamic value)
{
Console.WriteLine(value);
}
public static void GenericFunc(dynamic value)
{
Print(value);
}
static void Main(dynamic[] args)
{
GenericFunc((dynamic)"Hello World");
}