Parameter type using Generics constraint VS Explicit type declaration

Parameter type using Generics constraint VS Explicit type declaration

各自安好 发布于 2021-11-26 字数 639 浏览 838 回复 5 原文

What would be the difference between these two seemingly similar declarations?
When would you choose one syntax over another?

Is there any specific reason to choose one over the other?
Any performance penalties incurred for either case?

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"
}

如果你对这篇文章有疑问,欢迎到本站 社区 发帖提问或使用手Q扫描下方二维码加群参与讨论,获取更多帮助。

扫码加入群聊

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

寂寞美少年 2022-06-07 5 楼

You won't notice a difference on the function side, but you can see one on the caller side.

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

Import<MyFileInfo>(files,
                   (mfi) => Console.WriteLine("Import {0}", mfi.MyString));
So要识趣 2022-06-07 4 楼

In this case there isn't much difference, but say you want to limit it further for example you want T to have a default parameterless constructor. You can only do it the first way:

public void Import<T>(
        Func<IEnumerable<T>> getFiles, Action<T> import)
            where T : IFileInfo, new()
    {
            // Import files retrieved through "getFiles"
    }
離殇 2022-06-07 3 楼

There aren't any runtime performance penalties -- this is all handled by the compiler when generating IL for your code.

As for the syntax, I think the second makes it clearer that you are only interested in the IFileInfo interface.

韶华倾负 2022-06-07 2 楼

Although this questions has already been answered: Maybe you want to go with a less restrictive solution:

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

This one allows an Action<IFileInfo> and an Func<IEnumerable<ConcreteFileInfo>> to be passed.

忘年祭陌 2022-06-07 1 楼

The difference is that the first would allow you to pass in something which used a more concrete type implementing IFileInfo. For example:

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

(Where SpecialProperty is a property which exists on SpecialFileInfo but not IFileInfo.) You couldn't do this with the latter form.

There is a very slight execution-time penalty for generic methods and types - it will be JITted once for different each value type T type argument (don't forget a value type could implement IFileInfo) and once for all reference type (i.e. once it's been JITted or one reference type, it won't need to be JITted again). This will almost certainly be negligible in your real application though.