3

考虑到下面的应用程序代码,有 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();调用
    进入第一个方法:public
    static void Write(this IEnumerable source) // * *1
  • iEnuResult.Write(); (或 iEnuResult.Write();) 调用
    进入第二个方法:public static void Write1(this IEnumerable source)// * *2

如果要注释掉

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

然后

iEnuResult.Write1<object>(); 

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

如果同时评论第一种和第二种方法,则调用 3d 方法

iEnuResult.Write();

因此,可以<Type>在调用(调用)中调用带有和不带有 a 的“相同”方法,以及带有和不带有 a 的方法定义<Type>

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

4

1 回答 1

2

专注于您的两个问题:

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

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

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

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

  • 这是一种无需装箱和拆箱即可使用类型的方法(即object分别将值类型转换为 和从 )。正如这里所说:

    装箱和拆箱本身会导致显着的性能损失,但它也增加了托管堆的压力,导致更多的垃圾收集,这对性能不利。

如果您只有无类型方法 (3),则在IEnumerable枚举无类型时 ( IEnumerator.Currentreturns 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编译器可以推断泛型类型的类型的方法参数时。工厂方法通常属于此类。方法 likeT Create<T>()必须由 eg 调用Create<Customer>()。构造函数是另一个例子:没有指定类型甚至不能调用泛型构造函数。
  2. 当您想要强制使用特定的方法重载时。当继承类型混合了泛型和非泛型方法重载时,可能会发生这种情况。(顺便说一句,这不是良好设计的标志)。
  3. 间接地当类型在编译时不知道但仅在执行时。请参阅C# 中的泛型,使用变量的类型作为参数
于 2013-02-03T15:29:18.047 回答