In few words, what can be said about Func<>

可紊 提交于 2019-12-03 02:38:39

Func<> is a generic delegate - it is just very convenient to use, because you don't have to create your own delegate for each argument/return type combination.
Earlier, you had to write something like:

public delegate long MyDelegate( int number );

public void Method( IEnumerable<int> list, MyDelegate myDelegate )
{
    foreach( var number in list )
    {
        myDelegate( number );
    }
}

You had to publish your delegate so that a user can call your method correctly. Especially when you need a bunch of different delegates you ended up publishing one for every argument list and return type.
With Func<> you just write:

public void Method( IEnumerable<int> list, Func<int, long> myDelegate )
{
    foreach( var number in list )
    {
        myDelegate( number );
    }
}

It means the same as the first code example - Func<int, long> defines a delegate that takes one integer argument and returns a long value.

Of course you can use longer parameter lists, too: Func<int, int, bool, long> will still return a long value while it takes two ints and a bool value. If you wish a delegate without return value you will have to use Action<>, which will have void as a return type.

EDIT (by request): How to call the method in my example:

For the caller, there is no difference between the solution with MyDelegate or Func<>. In both cases he has three options to call the method:

Using a lambda notation (C# 3.0 required, probably the best solution for short methods):

Method( myList, i => i * i );

By using an anonymous method (C# 2.0 required):

Method( myList, delegate( int i )
{
    return i * i;
} );

Or by using a real method as an argument:

Method( myList, Square );

private static long Square( int number )
{
    return number * number;
}

Func<...> is a family of delegate types, that return some value, and take some number of arguments; for example:

  • Func<int,bool> is simply something that takes an int and returns a bool (the return is always at the end); for example a predicate:

    int[] data = {1,2,3,4,5};
    var odd = data.Where(i => i % 2 == 0);
    
  • Func<string> is a method that returns string, such as () => "hello world";.

  • Func<DateDtime, TimeSpan, DateTime> might be something like (when,howLong) => when + howLong;

Likewise there is Action<...> which does the same but without a return type.

There's nothing magic about Func<...> - it is just a simpler way of expressing delegates, while a: using generics (useful for LINQ), or b: not needing you to look up what the arguments are; if the delegate type is something obscure (PipeStreamImpersonationWorker for example) it can be hard to know what it takes; if that was expressed as the comparable Action it would be clear that it takes no parameters and returns void.

This might help. Suppose every time you see Func<int, string> you think to yourself:

interface IFuncIntString
{
    string Invoke(int x);
}

That is, the delegate is an object that implements this interface. It has a single method called Invoke which takes an int and returns a string.

Now add to that the feature that you can omit the "Invoke" on a call, and you've got yourself a delegate.

Func<int> (for example) is a type (in the way that string is a type). So you use it to declare variables, fields, parameters and so on.

It represents a computation that can be done whenever you ask it for an answer:

Func<int> f = () => DateTime.Now.Second;

// elsewhere...

Console.WriteLine( f() );

Note how you can call it just like a method. There are many overloaded versions of Func to support different numbers of parameters. The last type argument is the return type.

Func<int, string> quoteInt = n => "\"" + n + "\"";

Console.WriteLine( quoteInt(3) );

Func is a delegate type. You can declare your own, but it's easier to use Func. Where you want to return void, use Action instead of Func. You only need to declare custom delegates if you need out or ref parameters.

When assigning a lambda to a Func, you can refer to local variables. This is extremely powerful; it means that a Func is more than just code; it has data. So it's like an object with a single method (which technically it is - the method is called Invoke and the compiler implicitly calls that method for you when you call a delegate).

The syntax () => can be placed before any expression to say "don't do this now, delay it until later". It allows you to initialize a delegate capturing the delayed computation. And then the syntax () can be placed after the delegate to actually trigger the computation. So suffix () is kind-of the opposite of prefix () =>.

You can start with 101 Linq Samples.

In short, Func<> is a delegate where the last type parameter is the return type.

So, Func<int,bool> is a delegate that takes an int parameter and returns a bool.

Func<..., T> is delegate. where T is return-type, and all others - input parameters.

If you've ever used the => operator in c#, and you probably have, you've already used Funcs. You just haven't been explicitly declaring them.

So, if you write a statement like

var peopleWhoLikeBlue = people.Where(person => person.FavoriteColor == "Blue");

you're passing a Func<Person, bool> into the Where() method.

If you want to be wordy, you can rewrite that statement like this:

Func<Person, bool> favoriteColorIsBlue = person => person.FavoriteColor == "Blue";
var peopleWhoLikeBlue = people.Where(favoriteColorIsBlue);

And you'll get the same result.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!