繁体   English   中英

使用泛型的C#重载决策

[英]C# overload resolution with generics

我来自C ++背景,而且我对C#相对较新。 目前,我正在尝试编写两个打印函数,第一个接受通用数组参数(并将数组的项打印到命令行),第二个接受通用基本参数(并调用其ToString()方法)。 这是我的代码:

using System;

namespace OverloadResolution
{
  class Program
  {
    static void Main(string[] args)
    {
      string[] foo = new string[] { "A", "B", "C" };
      Extensions.PrintMe(foo);
      Extensions.PrintMe("Hello world");
      Console.ReadLine();
    }
  }

  public static class Extensions
  {
    public static void PrintMe<T>(T[] elm)
    {
      Console.WriteLine("PrintMe<T>(T[] elm)");
      Console.WriteLine(string.Join("", elm));
    }

    public static void PrintMe<T>(T elm)
    {
      Console.WriteLine("PrintMe<T>(T elm)");
      Console.WriteLine(elm.ToString());
    }
  }
}

一切都按预期工作,并选择正确的重载。 但是,如果我更改我的代码如下:

using System;

namespace OverloadResolution
{
  class Program
  {
    static void Main(string[] args)
    {
      string[] foo = new string[] { "A", "B", "C" };
      Extensions.PrintMe2(foo); // <<< Note the PrintMe2 function
      Extensions.PrintMe2("Hello world"); // <<< Note the PrintMe2 function
      Console.ReadLine();
    }
  }

  public static class Extensions
  {
    public static void PrintMe2<T>(T elm)
    {
      PrintMe(elm);
    }

    public static void PrintMe<T>(T[] elm)
    {
      Console.WriteLine("PrintMe<T>(T[] elm)");
      Console.WriteLine(string.Join("", elm));
    }

    public static void PrintMe<T>(T elm)
    {
      Console.WriteLine("PrintMe<T>(T elm)");
      Console.WriteLine(elm.ToString());
    }
  }
}

调用PrintMe2函数时,类型信息似乎丢失,因为在内部,在两种情况下都会调用第二个PrintMe函数。 在这种情况下是否有适用的特殊规则? 或者我错过了什么? 我使用C#7.0和.NET framework 4.7。 我应该注意到,我已经了解到与C ++模板相比,C#泛型的使用非常有限......

在编译PrintMe2 ,我们必须执行重载决策以确定调用哪个PrintMe方法,并且我们必须将正确的方法标记发送到PrintMe2的IL中以识别该方法。

在编译PrintMe2 ,我们不知道其T类型参数的性质。 它可能是任何东西。 的唯一版本PrintMe即同样无限制是PrintMe<T>(T elm) 因此,我们将特定方法的方法标记发送到IL中。

泛型与模板不同 ,最显着的是因为它们与可能使用它们的任何代码分开编译的。 我们有自己的编译时做出决定,以及这些决定必须为所有可能的类型参数是有效的(受应用于类/方法,其中类型参数(一个或多个)声明任何类型的约束)

如果你想要一个只根据传入的参数的运行时类型进行重载解析的方法,你可以使用dynamic ,但这非常难看并带来很多开销。 它也可能导致运行时错误,没有特定的重载是某些用例最特殊的。

您可以将参数强制转换为伪类型dynamic以强制C#编译器根据参数的实际值选择最具体的重载,如下所示:

PrintMe((dynamic)elm);

但是,如果检查生成的IL代码,则会产生运行时损失,因此应谨慎使用dynamic关键字。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM