Func委托现实世界的使用

发布于 2024-11-10 15:21:55 字数 597 浏览 3 评论 0原文

我最近一直在使用委托 Func 并创建返回包含 lambda 的不同实例 Func 的方法,但我一直在努力提出的是任何关于为什么人们想要返回(甚至创建这样一个实例)的现实世界的好想法。

MSDN 上有一个示例,他们执行以下操作...

Func<string, string> convertMethod = UppercaseString;
private static string UppercaseString(string inputString)
{
    return inputString.ToUpper();
}

并且尽管它看起来很漂亮并且是一个有趣的概念,但我看不出这样的代码提供了什么优势。

那么,这里有人可以提供任何现实世界中他们必须使用 Func的示例吗?一般来说,为什么人们可能想要使用这个委托?

I've recently been playing around with the delegate Func<T, TResult> and creating methods that return different instances Func<T, TResult> containing lambda but what I have struggled to come up with is any good real world ideas of why one might want to return (or even create such an instance).

There is an example on MSDN where they do the following...

Func<string, string> convertMethod = UppercaseString;
private static string UppercaseString(string inputString)
{
    return inputString.ToUpper();
}

And although it looks pretty and is an interesting concept I fail to see what advantages such code provides.

So could someone here please provide any real world examples where they have had to use Func<T, TResult> and in general why one might want to use this delegate?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

青巷忧颜 2024-11-17 15:21:55

如果您真正问的是为什么我们一般都有委托:

  • 如果您曾经使用过事件,那么您就使用过委托
  • 如果您曾经使用过 LINQ,那么您就使用过委托(从技术上讲,对于 IQueryable 提供程序(您使用了表达式,但对于 LINQ-to-Objects,您使用了委托)

委托提供了一种将您自己的行为注入到另一个对象中的方法。最常见的用法是与事件一起使用。对象公开一个事件,并且您提供一个函数(无论是否匿名),该函数在该事件触发时被调用。

如果您问为什么我们有 Func (和类似的)委托,那么有两个主要原因:

  1. 人们在需要特定的委托时必须声明自己的简单委托类型在他们的代码中委托。虽然 Action<>Func<> 委托无法涵盖所有​​情况,但它们提供起来很简单,并且涵盖了许多需要自定义代表的情况。
  2. 更重要的是,Func 委托在 LINQ-to-Objects 中广泛用于定义谓词。更具体地说,Func。这允许您定义一个谓词,该谓词采用 IEnumerable的强类型成员并使用 lambda 或普通函数返回布尔值,然后将该谓词传递给 LINQ-to-Objects 。

If what you're asking, really, is why we have delegates in general:

  • If you've ever consumed an event, you've used a delegate
  • If you've ever used LINQ, you've used a delegate (technically, with an IQueryable provider you've used an expression, but for LINQ-to-Objects you've used a delegate)

Delegates provide a way of injecting your own behavior into another object. The most common usage is with events. An object exposes an event and you provide a function (anonymous or not) that gets called when that event fires.

If you're asking why we have the Func<T, TResult> (and similar) delegate, then there are two main reasons:

  1. People were having to declare their own simple delegate types when they needed a particular delegate in their code. While the Action<> and Func<> delegates can't cover all cases, they are simple to provide and cover many of the cases where custom delegates were needed.
  2. More importantly, the Func<T, TResult> delegate is used extensively in LINQ-to-Objects to define predicates. More specifically, Func<T, bool>. This allows you to define a predicate that takes a strongly-typed member of an IEnumerable<T> and returns a boolean by using either a lambda or ordinary function, then pass that predicate to LINQ-to-Objects.
童话 2024-11-17 15:21:55

您会在 LINQ 中经常使用它。例如,将列表中的所有数字加倍:

myList.Select(x => x * 2);

这是一个 Func。创建简洁的代码时它非常有用。一个现实世界的例子是在我制作的众多塔防游戏之一中,我使用一行计算了距离塔最近的敌人:

enemies.Select(x => tower.Location.DistanceTo(x.Location)).OrderBy(x => x).FirstOrDefault();

You would use it a lot in LINQ. So, for example, to double all the numbers in a list:

myList.Select(x => x * 2);

That's a Func<TIn, TOut>. It's quite useful when creating concise code. A real-world example is in one of the many tower-defence games I made, I calculated the closest enemy to the tower using one line:

enemies.Select(x => tower.Location.DistanceTo(x.Location)).OrderBy(x => x).FirstOrDefault();
贩梦商人 2024-11-17 15:21:55

我认为一个很好的例子是延迟初始化。

var value = new Lazy<int>(() => ExpensiveOperation()); // Takes Func<T>

I think a great example is lazy initialization.

var value = new Lazy<int>(() => ExpensiveOperation()); // Takes Func<T>
朕就是辣么酷 2024-11-17 15:21:55

需要函数指针的典型示例是将比较函数传递给排序例程。为了具有不同的排序键,您可以为比较函数创建一个 lambda,并将其传递给排序函数。

或者举一个简单的现实示例:

IEnumerable<Person> FindByLastName(string lastName)
{
    return Customers.Where(cust => cust.LastName == lastName);
}

在此示例中,cust => cust.LastName == lastName 不仅仅是一个 lambda,它还通过捕获 lastName 参数创建一个闭包。换句话说,它创建一个函数,每次调用FindByLastName时该函数都会不同。

The canonical example of a need for a function pointer is for a comparison function to pass to a sort routine. In order to have different sort keys, you create a lambda for the comparison function, and pass that to the sort function.

Or for a simple real-world example:

IEnumerable<Person> FindByLastName(string lastName)
{
    return Customers.Where(cust => cust.LastName == lastName);
}

In this example, cust => cust.LastName == lastName is not just a lambda, but it creates a closure by capturing the lastName parameter. In othe words, it creates a function, which will be different every time FindByLastName is called.

左耳近心 2024-11-17 15:21:55

Func 委托(和其他重载)为您提供了在 C# 中编写抽象的新方法。为了演示一些选项,这里有几个可以使用委托编写的 C# 语言构造:

Thread.Lock(obj, () => { 
    // Safely access 'obj' here
});

Enumerable.ForEach(collection, element => {
    // Process 'element'
});

Exceptions.Try(() => { 
    // Try block
}).With((IOException e) => {
    // Handle IO exceptions
});

这些构造非常原始,因此最好为它们提供一个语言构造。然而,它表明 Func 和 lambda 表达式增加了相当多的表达能力。它使得编写新的构造成为可能,例如并行循环(使用.NET 4.0):

Parallel.ForEach(collection, element => {
    // Process 'element'
});

The Func<T> delegate (and other overloads) give you new ways for writing abstractions in C#. To demonstrate some of the options, here are a couple of C# langauge constructs that could be written using delegates instead:

Thread.Lock(obj, () => { 
    // Safely access 'obj' here
});

Enumerable.ForEach(collection, element => {
    // Process 'element'
});

Exceptions.Try(() => { 
    // Try block
}).With((IOException e) => {
    // Handle IO exceptions
});

These are quite primitive, so it is good to have a language construct for them. However, it demonstrates that Func and lambda expressions add quite a lot of expressive power. It makes it possible to write new constructs such as parallel loop (using .NET 4.0):

Parallel.ForEach(collection, element => {
    // Process 'element'
});
风向决定发型 2024-11-17 15:21:55

首先,Func 不是一个类,它是一个委托。

基本上,如果您不想为此声明自己的委托,则只要需要方法参数或委托类型的属性,就可以使用它。

First of all, Func<T> is not a class, it's a delegate.

Basically, you can use it whenever you need a method argument or a property of delegate type if you don't want to declare your own delegate for that.

零度° 2024-11-17 15:21:55

除了嵌入到许多框架(例如 LINQ、模拟工具和依赖注入容器)中这一事实之外,Funct 的一大用途是使用它来创建 基于委托的工厂

One great use of Funct<T>, besides the fact that it is embedded in many frameworks such as LINQ, Mocking Tools, and Dependency Injection containers is to use it to create a delegate based factory.

泅渡 2024-11-17 15:21:55

最近,我希望调用我的方法的外部程序能够修改它的行为方式。

我的方法本身只是将文件从 XLS 转换为 XML。但有必要允许调用代码在需要时指定任意数量的转换,这些转换应在写入为 xml 标记之前应用于每个 xls 单元格。例如:将“,”小数分隔符转换为“.”,抑制千位分隔符等等(转换都是字符串替换)。

然后,调用者代码只需在字典中添加任意数量的条目,其中键是模式,值是该模式的替换字符串。我的方法循环遍历字典并为每个条目创建一个新的 Func 。然后对于每个单元格,按顺序应用 Func

Recently, I wanted the external program calling my method to be able to modify the way it behaves.

My method in itself simply converts a file from XLS to XML. But it was necessary to allow the calling code to specify if needed an arbitrary number of transformations which should apply to each xls cell before being writing as a xml tag. For example : convert the "," decimal separator to ".", suppress the thousand separator, and so on (the transformations were all string replacements).

Then the caller code just had to add an arbitrary number of entries in a dictionary where the key is the pattern and the value is the replacement string for this pattern. My method loops over the dictionary and creates a new Func<string,string> for each entry. Then for each cell the Func<string,string> are applied in sequence.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文