How do you use Func<> and Action<> when desi

2019-01-29 17:42发布

All the examples I can find about Func<> and Action<> are simple as in the one below where you see how they technically work but I would like to see them used in examples where they solve problems that previously could not be solved or could be solved only in a more complex way, i.e. I know how they work and I can see they are terse and powerful, so I want to understand them in a larger sense of what kinds of problems they solve and how I could use them in the design of applications.

In what ways (patterns) do you use Func<> and Action<> to solve real problems?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestFunc8282
{
    class Program
    {
        static void Main(string[] args)
        {
            //func with delegate
            Func<string, string> convert = delegate(string s)
            {
                return s.ToUpper();
            };

            //func with lambda
            Func<string, string> convert2 = s => s.Substring(3, 10);

            //action
            Action<int,string> recordIt = (i,title) =>
                {
                    Console.WriteLine("--- {0}:",title);
                    Console.WriteLine("Adding five to {0}:", i);
                    Console.WriteLine(i + 5);
                };

            Console.WriteLine(convert("This is the first test."));
            Console.WriteLine(convert2("This is the second test."));
            recordIt(5, "First one");
            recordIt(3, "Second one");

            Console.ReadLine();

        }
    }
}

9条回答
等我变得足够好
2楼-- · 2019-01-29 18:11

By keeping them generic and supporting multiple arguments, it allows us to avoid having to create strong typed delegates or redundant delegates that do the same thing.

查看更多
叛逆
3楼-- · 2019-01-29 18:14

Actually, i found this at stackoverflow (at least - the idea):

public static T Get<T>  
    (string cacheKey, HttpContextBase context, Func<T> getItemCallback)
            where T : class
{
    T item = Get<T>(cacheKey, context);
    if (item == null) {
        item = getItemCallback();
        context.Cache.Insert(cacheKey, item);
    }

    return item;
}
查看更多
看我几分像从前
4楼-- · 2019-01-29 18:16

I use the Action and Func delegates all the time. I typically declare them with lambda syntax to save space and use them primarily to reduce the size of large methods. As I review my method, sometimes code segments that are similar will stand out. In those cases, I wrap up the similar code segments into Action or Func. Using the delegate reduces redundant code, give a nice signature to the code segment and can easily be promoted to a method if need be.

I used to write Delphi code and you could declare a function within a function. Action and Func accomplish this same behavior for me in c#.

Here's a sample of repositioning controls with a delegate:

private void Form1_Load(object sender, EventArgs e)
{
    //adjust control positions without delegate
    int left = 24;

    label1.Left = left;
    left += label1.Width + 24;

    button1.Left = left;
    left += button1.Width + 24;

    checkBox1.Left = left;
    left += checkBox1.Width + 24;

    //adjust control positions with delegate. better
    left = 24;
    Action<Control> moveLeft = c => 
    {
        c.Left = left;
        left += c.Width + 24; 
    };
    moveLeft(label1);
    moveLeft(button1);
    moveLeft(checkBox1);
}
查看更多
5楼-- · 2019-01-29 18:17

They're also handy for refactoring switch statements.

Take the following (albeit simple) example:

public void Move(int distance, Direction direction)
{
    switch (direction)
    {
        case Direction.Up :
            Position.Y += distance;
            break;
        case Direction.Down:
            Position.Y -= distance;
            break;
        case Direction.Left:
            Position.X -= distance;
            break;
        case Direction.Right:
            Position.X += distance;
            break;
    }
}

With an Action delegate, you can refactor it as follows:

static Something()
{
    _directionMap = new Dictionary<Direction, Action<Position, int>>
    {
        { Direction.Up,    (position, distance) => position.Y +=  distance },
        { Direction.Down,  (position, distance) => position.Y -=  distance },
        { Direction.Left,  (position, distance) => position.X -=  distance },
        { Direction.Right, (position, distance) => position.X +=  distance },
    };
}

public void Move(int distance, Direction direction)
{
    _directionMap[direction](this.Position, distance);
}
查看更多
老娘就宠你
6楼-- · 2019-01-29 18:17

I use an Action to nicely encapsulate executing database operations in a transaction:

public class InTran
{
    protected virtual string ConnString
    {
        get { return ConfigurationManager.AppSettings["YourDBConnString"]; }
    }

    public void Exec(Action<DBTransaction> a)
    {
        using (var dbTran = new DBTransaction(ConnString))
        {
            try
            {
                a(dbTran);
                dbTran.Commit();
            }
            catch
            {
                dbTran.Rollback();
                throw;
            }
        }
    }
}

Now to execute in a transaction I simply do

new InTran().Exec(tran => ...some SQL operation...);

The InTran class can reside in a common library, reducing duplication and provides a singe location for future functionality adjustments.

查看更多
我想做一个坏孩纸
7楼-- · 2019-01-29 18:19

I have a separate form that accepts a generic Func or an Action in the constructor as well as some text. It executes the Func/Action on a separate thread while displaying some text in the form and showing an animation.

It's in my personal Util library, and I use it whenever I want to do a medium length operation and block the UI in a non-intrusive way.

I considered putting a progress bar on the form as well, so that it could perform longer running operations but I haven't really needed it to yet.

查看更多
登录 后发表回答