参数类型使用泛型约束VS显式类型声明

时间:2009-04-27 18:30:19

标签: c# .net generics

这两个看似相似的声明有什么区别? 你何时会选择一种语法而不是另一种?

有没有具体的理由选择其中一个?
两种情况都会导致任何性能损失吗?

public void Import<T>(
    Func<IEnumerable<T>> getFiles, Action<T> import)
        where T : IFileInfo
{
        // Import files retrieved through "getFiles"
}

public void Import(
        Func<IEnumerable<IFileInfo>> getFiles, Action<IFileInfo> import)
{
        // Import files retrieved through "getFiles"
}

5 个答案:

答案 0 :(得分:3)

不同之处在于,第一个允许您传递使用更具体类型实现IFileInfo的内容。例如:

Func<IEnumerable<SpecialFileInfo>> lister = () => ListFiles();
Import(lister, file => Console.WriteLine(file.SpecialProperty));

(其中SpecialPropertySpecialFileInfo但不存在IFileInfo的属性。)您无法使用后一种形式执行此操作。

泛型方法和类型的执行时间损失非常小 - 对于不同的每个值类型T类型参数,它将被JIT一次(不要忘记值类型可以实现IFileInfo )并且对于所有引用类型(即,一旦它被JIT或一个引用类型,它将不需要再次被JIT)。这几乎可以肯定在您的实际应用中可以忽略不计。

答案 1 :(得分:2)

虽然这些问题已经得到解答:也许您希望采用限制较少的解决方案:

public void Import<T,S>(
        Func<IEnumerable<S>> getFiles, Action<T> import)
            where T : IFileInfo
            where S : T
    {
            // Import files retrieved through "getFiles"
    }

这个允许传递Action<IFileInfo>Func<IEnumerable<ConcreteFileInfo>>

答案 2 :(得分:1)

没有任何运行时性能损失 - 这些都是在为代码生成IL时由编译器处理的。

至于语法,我认为第二个更清楚你只对IFileInfo接口感兴趣。

答案 3 :(得分:1)

在这种情况下没有太大的区别,但是你想进一步限制它,例如你希望T有一个默认的无参数构造函数。你只能这样做:

public void Import<T>(
        Func<IEnumerable<T>> getFiles, Action<T> import)
            where T : IFileInfo, new()
    {
            // Import files retrieved through "getFiles"
    }

答案 4 :(得分:1)

您不会注意到功能方面的差异,但您可以在呼叫方看到一个。

public class MyFileInfo : IFileInfo
{
  public string MyString { get; set; }
}

Import<MyFileInfo>(files,
                   (mfi) => Console.WriteLine("Import {0}", mfi.MyString));