簡體   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