C# 设计应用程序时如何使用 Func<> 和 Action<>?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1537404/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you use Func<> and Action<> when designing applications?
提问by Edward Tanguay
All the examples I can find about Func<> and Action<> are simpleas in the one below where you see howthey 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 senseof what kinds of problems they solve and how I could use them in the design of applications.
我能找到的有关 Func<> 和 Action<> 的所有示例都很简单,如下所示,您可以看到它们在技术上是如何工作的,但我希望看到它们用于解决以前无法解决或可以解决的问题的示例中只能以更复杂的方式解决,即我知道它们是如何工作的,我可以看到它们简洁而强大,所以我想从更大的意义上理解它们,它们解决了什么样的问题,以及我如何在这些问题中使用它们应用程序的设计。
In what ways (patterns) do you use Func<> and Action<> to solve real problems?
你以什么方式(模式)使用 Func<> 和 Action<> 来解决实际问题?
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();
}
}
}
采纳答案by Craig Vermeer
They're also handy for refactoring switch statements.
它们对于重构 switch 语句也很方便。
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:
使用 Action 委托,您可以将其重构如下:
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);
}
回答by Daniel A. White
Using linq.
使用 linq。
List<int> list = { 1, 2, 3, 4 };
var even = list.Where(i => i % 2);
The parameter for Where
is an Func<int, bool>
.
的参数Where
是一个Func<int, bool>
。
Lambda expressions are one of my favorite parts of C#. :)
Lambda 表达式是我最喜欢的 C# 部分之一。:)
回答by Arnis Lapsa
Actually, i found this at stackoverflow (at least - the idea):
实际上,我在 stackoverflow 上发现了这个(至少 - 这个想法):
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;
}
回答by Yannick Motton
One thing I use it for is Caching of expensive method calls that never change given the same input:
我使用它的一件事是缓存昂贵的方法调用,这些调用在相同输入的情况下永远不会改变:
public static Func<TArgument, TResult> Memoize<TArgument, TResult>(this Func<TArgument, TResult> f)
{
Dictionary<TArgument, TResult> values;
var methodDictionaries = new Dictionary<string, Dictionary<TArgument, TResult>>();
var name = f.Method.Name;
if (!methodDictionaries.TryGetValue(name, out values))
{
values = new Dictionary<TArgument, TResult>();
methodDictionaries.Add(name, values);
}
return a =>
{
TResult value;
if (!values.TryGetValue(a, out value))
{
value = f(a);
values.Add(a, value);
}
return value;
};
}
The default recursive fibonacci example:
默认递归斐波那契示例:
class Foo
{
public Func<int,int> Fibonacci = (n) =>
{
return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
};
public Foo()
{
Fibonacci = Fibonacci.Memoize();
for (int i=0; i<50; i++)
Console.WriteLine(Fibonacci(i));
}
}
回答by Hasani Blackwell
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.
通过保持它们的通用性并支持多个参数,它允许我们避免创建强类型委托或做同样事情的冗余委托。
回答by Steve
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.
我一直使用Action
和Func
代表。我通常使用 lambda 语法声明它们以节省空间并主要使用它们来减少大型方法的大小。当我回顾我的方法时,有时相似的代码段会脱颖而出。在这些情况下,我将类似的代码段包装到Action
or 中Func
。使用委托减少了冗余代码,为代码段提供了一个很好的签名,如果需要,可以轻松地将其提升为方法。
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#.
我曾经写过 Delphi 代码,你可以在一个函数中声明一个函数。Action 和 Func 在 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);
}
回答by Steven Evers
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.
我有一个单独的表单,它接受构造函数中的通用 Func 或 Action 以及一些文本。它在单独的线程上执行 Func/Action,同时在表单中显示一些文本并显示动画。
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.
它在我个人的 Util 库中,每当我想做中等长度的操作并以非侵入性的方式阻塞 UI 时,我都会使用它。
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.
我也考虑在表单上放置一个进度条,以便它可以执行更长时间的运行操作,但我还没有真正需要它。
回答by Todd Stout
I use an Action to nicely encapsulate executing database operations in a transaction:
我使用 Action 很好地封装了在事务中执行的数据库操作:
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.
InTran 类可以驻留在公共库中,从而减少重复并为未来的功能调整提供单一位置。
回答by Craig Vermeer
Dunno if it's bad form to answer the same question twice or not, but to get some ideas for better uses of these types in general I suggest reading Jeremy Miller's MSDN article on Functional Programming:
不知道两次回答相同的问题是否不好,但是为了获得一些更好地使用这些类型的想法,我建议阅读 Jeremy Miller 的 MSDN 函数式编程文章: