Reputation: 36895
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
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
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
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
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
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