dance2die
dance2die

Reputation: 36895

Parameter type using Generics constraint VS Explicit type declaration

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

Upvotes: 0

Views: 597

Answers (5)

Marcel Jackwerth
Marcel Jackwerth

Reputation: 54752

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.

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1500065

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.

Upvotes: 3

Samuel
Samuel

Reputation: 38346

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));

Upvotes: 1

BFree
BFree

Reputation: 103740

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

Upvotes: 1

mqp
mqp

Reputation: 71937

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.

Upvotes: 1

Related Questions