tags:

views:

267

answers:

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"
}
+1  A: 

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.

mquander
+1  A: 

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"
    }
BFree
+1 for something I have not considered.
Sung Meister
+1  A: 

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));
Samuel
+3  A: 

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.

Jon Skeet
Thanks, Jon. I wasn't aware of execution delay caused by generic methods/types. I doubt that it would cause significant performance penalty in my application.
Sung Meister
Indeed, it's almost always negligible - and it's only incurred at most once per type argument, i.e. if you use Foo<int> and later use Foo<int> again, it'll use the code JITted earlier.
Jon Skeet
+1  A: 

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.

Marcel J.
This is awesome.
Sung Meister