为什么我应该在方法<类型>() 中指定<类型>?以及如何使用它

本文关键字:类型 何使用 我应该 方法 为什么 | 更新日期: 2023-09-27 17:56:51

考虑到下面的应用程序代码,有 3 个重载的扩展方法做同样的事情,并且具有相同的输入和输出:

  • 使用调用和定义方法的参数有什么好处(或区别)?
  • 为什么要使用它们(如果将调用没有它们的相同方法 3 并执行相同的操作)?
  • 或者如何在方法中手动/显式使用它们(此类信息)?

法典:

namespace LINQ_CreatingYourFirstExtensionMethod   
{
  internal class Program  
  {
    private static void Main(string[] args)  
    {
      string[] aBunchOfWords = {"One", "Two", "Hello", "World", "Four", "Five"};  
      var iEnuResult =  from s in aBunchOfWords   
                        where s.Length == 5  
                        select s;
      iEnuResult.Write();  
      iEnuResult.Write<string>();
      iEnuResult.Write<object>();//same effect as above line
      Console.ReadKey();
    }  
  }  
} 

重载的扩展方法 Write():

namespace LINQ_CreatingYourFirstExtensionMethod  
{  
   public static class Utils  
   {
     public static void Write(this IEnumerable<object> source) //****1 
     //public static void Write(this IEnumerable<string> source)//same effects as above line  
     {
       foreach (var item in source)  
       {
         Console.WriteLine(item);
       }
     }
    public static void Write<T>(this IEnumerable<T> source)//****2
    {
      foreach (var item in source)
      {
        Console.WriteLine(item);
      }
    }
    public static void Write(this IEnumerable source)//******3
    {
      foreach (var item in source)
      {
        Console.WriteLine(item);
      }
    }
  }
}

更新:
你能给我任何最简单的例子为什么我需要

  1. 使用 <Type> 调用方法
  2. 使用 <Type> 定义方法

如果我可以在没有它的情况下做同样的事情?

更新2:
我没有立即写它,因为我认为从问题的上下文中很明显。

在当前代码中:

  • iEnuResult.Write();电话
    输入第一种方法:
    公共静态空 写入(此 IE无数源)//**1
  • iEnuResult.Write();(或 iEnuResult.Write();)叫
    进入第二种冰毒:公共静态空 Write1(此 IEnumerable 源)//**2

如果要注释掉

public static void Write1<T>(this IEnumerable<T> source)//*****2

然后

iEnuResult.Write1<object>(); 

无法制作(仅iEnuResult.Write();

如果要同时注释第 1 种和第 2 种方法,则调用 3d 方法

iEnuResult.Write();

因此,可以在调用(调用)中使用和不使用<Type>调用"相同"方法,也可以具有带和不带<Type>的方法定义。

有多种组合(我会说几十种)来做看似相同的事情,我看不出有什么理由。
所以,我想了解这种差异存在的目的是什么,如果有的话

为什么我应该在方法<类型>() 中指定<类型>?以及如何使用它

重点回答您的两个问题:

  1. 为什么要使用 <Type> 调用方法
  2. 为什么要使用 <Type> 定义方法

先问第二个问题。让我改写一下:我什么时候定义泛型方法?

当泛型方法面向许多类型,但一次只针对一种类型时,您将定义该方法。有两个很大的优势:

  • 它确保(编译时)类型安全:IEnumerable<string>实际上只包含字符串,而不是奇数整数或其他任何东西。

  • 这是一种使用类型而不装箱和取消装箱的方法(即分别将值类型与object相互转换)。正如这里所说:

    箱和取消装箱本身会导致显著的性能损失,但它也会增加托管堆的压力,从而导致更多的垃圾回收,这对性能不利。

如果只有非类型化方法 (3),则在枚举非类型化IEnumerable时,每个字符串都会装箱(IEnumerator.Current返回 Object ),并再次取消装箱以调用特定于类型的 ToString() 方法。源列表可以包含任何内容(这在这里无关紧要,但通常如此)。

通用方法 (2) 跳过装箱和取消装箱,并且是类型安全的。

第一种方法强制将任何输入参数(显式或隐式)转换为IEnumerable<object> 。同样,将发生装箱和拆箱。但另一个令人讨厌的事情是,并不总是有隐式转换可用,这会迫使该方法的使用者在调用它之前显式执行转换。其效果可以通过将select s更改为select s.Length来说明。如果只有方法 1 可用,您将获得

实例参数:无法从'System.Collections.Generic.IEnumerable<int>'转换为'System.Collections.Generic.IEnumerable<object>'

我认为一般的经验法则是避免使用object(或IEnumerable<object>等)类型的方法参数,除非没有其他选择。

简而言之:您的第二种方法是这里的最佳选择,因为它可以执行任何类型的任务,但避免装箱和取消装箱。

现在你的第一个问题。何时需要在方法调用中指定泛型类型参数?我能想到三个原因(可能还有更多):

  1. 当没有类型为 T 的方法参数时,编译器可以通过该参数推断泛型类型。工厂方法通常属于此类别。像 T Create<T>() 这样的方法必须通过以下方式调用,例如 Create<Customer>() .构造函数是另一个示例:如果没有指定的类型,甚至无法调用泛型构造函数。
  2. 当您想要强制使用特定方法重载时。当继承类型混合了泛型和非泛型方法重载时,可能会发生这种情况。(顺便说一下,这不是好设计的标志)。
  3. 间接地在编译时不知道类型,而仅在执行时知道。请参阅 C# 中的泛型,使用变量的类型作为参数。