简体   繁体   中英

How to use Func<> as parameter

I want to use the Func as parameter to delegate param, like below:

delegate IPic Creator( Node pnode );
int CalSize( Creator c );
Func<Node,Ipic> funcCreator = ... ;
//then I want to use calSize
calsize( funcCreator ); // error
calsize( funcCreator.invoke ); // error

Error message is the following:

Argument type 'System.Func<...Node, ...IPic>' is not assignable to parameter type '...Creator'.

So, as the code show, I want to use Func as params. How should I do?

There are many ways to do this.

  1. You can define a delegate which executes funcCreator and pass it to a function:

     Creator cr = x => funcCreator(x); CalSize(cr); 

    which is the same as

     CalSize(x => funcCreator(x)); 
  2. Create a delegate from your funcCreator :

     CalSize(new Creator(funcCreator)); 
  3. Pass .Invoke method:

     CalSize(funcCreator.Invoke); 

As for me, I would consider changing the method definition to:

int CalSize(Func<Node, IPic> c);

to make it easier to work with your function.
I did not find it useful to use delegates, and do not use them at all by now. Of course, it is just my opinion and experience. If your project successfully utilizes delegates, then you can just ignore this part :)

Performance

For performance test, I have modified your code so that Creator takes double and returns double (since I don't have Node and IPic ).

I have used the following code:

private static double lastResult;
// lastResult is used so that calculation within methods is not optimized away

public static void CalSize(Creator c)
{
    lastResult = c(10.0); 
}

public static void CalSize2(Func<double, double> f)
{
    lastResult = f(10.0);
}

static void Main()
{
    Func<double, double> funcCreator = x => Math.Pow(x, 20);

    Stopwatch sw = new Stopwatch();
    sw.Start();

    for (int i = 0; i < 10000000; i++)
    {
        // measured code goes here
    }

    sw.Stop();
}

Result are the following for difference approaches:

1. CalSize(x => funcCreator(x)); -> 579 ms
2. CalSize(new Creator(funcCreator)); -> 625 ms
3. CalSize(funcCreator.Invoke); -> 568 ms
4. CalSize2(funcCreator); -> 467 ms

So, the least performance approach is new Creator since it takes some time to construct a delegate. The first and the third approaches are the same, because they actually do the same thing. The most performant approach is the one of Func function argument which is described in the end of my answer with about 20% of advantage.

Also, note that it took 10 000 000 operations to make the difference of ~100 ms. Imagine how many of these operations you are going to do, and, most probably, you will understand that this difference is absolutely insignificant. Just choose the approach which is convenient for you and don't mind about performance.

You need to wrap your Func<> into a delegate:

(Creator)(pnode => funcCreator(pnode))

See this answer for the exact details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM