在重载方法上使用泛型参数
本文关键字:泛型 参数 重载 方法 | 更新日期: 2023-09-27 18:34:15
为什么这个程序输出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# 的后台转换的?
重载解析仅在编译时完成。
由于GenericFunc<T>
在编译时不知道T
是string
还是其他东西,因此它只能使用"重载"Print<T>(T value)
。
使用 dynamic
,您可以将其更改为动态调度,并获得预期的行为:
Print((dynamic)value);
这使得重载解析在运行时发生,实际运行时类型为 value
。
简单问题的简单答案
另一个答案解释了泛型的绑定方式(编译时(。但它并没有回答OOP,良好实践,或者为什么你不应该首先编写这段代码。
哎呀
OOP 中的第一个 O 表示对象,没有只有静态方法。
责任
让我们将该方法的 Generic 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);
}
对于那些知道为什么你不应该使用动态的人,除非在某些情况下(见我的安维尔(。
更清洁的 OOP 解决方案
现在想象一下,您要打印不同的对象。每个对象都应该负责知道如何显示它。首先,因为它通过不向外部世界泄露内部数据来简化数据的封装。其次,因为内部数据和打印函数之间有固有的耦合,所以两者都应该位于同一个地方:类内部。这就是ToString
函数的目的。
让我们采取一些高度...
现在,我们可以想象它不是一个打印功能,而是其他东西。
我们得到了一个在同一函数上具有重载的类层次结构(我们称之为 Foo
(,以及这些类的实例集合,您必须为其调用函数Foo
。然后让我们让所有这些类实现IFooCallable
接口:
public interface IFooCallable
{
void Foo();
}
有点复杂...
好的,但是想象一下,没有通用的方法来处理所有这些类实例,因为存在非常不同的实例。
我们称之为访客模式。当您想要分析每个节点非常不同的某些对象树时,通常会使用它(如在 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");
}