简体   繁体   English

将方法作为参数直接传递给调用方法

[英]Passing methods as parameter vs calling methods directly

I have seen methods passed as parameters in some examples. 我已经看到在一些例子中作为参数传递的方法。 If I can call one method from another method, why should I pass method as a parameter? 如果我可以从另一个方法调用一个方法,为什么我应该将方法作为参数传递? What is the purpose behind this design? 这个设计背后的目的是什么?

  1. Calling one method from another 从另一个方法调用一个方法
  2. Passing method as parameter using delegate or Action 使用delegate或Action将方法作为参数传递

Passing in a method as a parameter can be used to prevent dependencies and coupling. 传递方法作为参数可用于防止依赖性和耦合。 Let's take a look at how this can be used for the Strategy pattern: 让我们来看看它如何用于策略模式:

Let's say we have a method PrintReport , which prints a given list of items, which might be sorted by Name or by Type, based on a parameter. 假设我们有一个方法PrintReport ,它打印一个给定的项目列表,可以根据参数按名称或类型排序。 This is the naive approach: 这是天真的方法:

public void PrintReport (List<Item> data, SortOrder sortBy)
{
    List<Item> sortedItems;
    switch (sortBy)
    {
        case SortOrder.Name: sortedItems = SortByName(data); break;
        case SortOrder.Type: sortedItems = SortByType(data); break;
    }

    Print(sortedItems);
}

It's simple but it works. 它很简单,但它的工作原理。 But what happens when we want to add a new sort order? 但是当我们想要添加新的排序顺序时会发生什么? We need to update the SortOrder enum, go into PrintReport and add a new case and call the new SortByWhatever method. 我们需要更新SortOrder枚举,进入PrintReport并添加一个新case并调用新的SortByWhatever方法。

But if we passed in a method as a parameter, our PrintReport can be simpler and not care about the sort implementation: 但是如果我们将方法作为参数传递,我们的PrintReport可以更简单,而不关心排序实现:

public void PrintReport (List<Item> data, Func<List<Item>, List<Item>> sorter)
{
    List<Item> sortedItems = sorter(data);
    Print(sortedItems);
}

Now the sorting function can be defined anyway, possibly even in a different assembly that PrintReport isn't even aware of. 现在无论如何都可以定义排序功能,甚至可能在PrintReport甚至不知道的不同组件中。 It can be a lambda function or an anonymous method defined ad-hoc. 它可以是lambda函数或ad-hoc定义的匿名方法。 But in all cases, our method will receive the delegate, use it to sort, and then print the report. 但在所有情况下,我们的方法将接收委托,使用它进行排序,然后打印报告。

Here's a usage example. 这是一个用法示例。 At first it looks like we merely moved the switch/case outside of the function, which is important enough since it allows different callers to have different logic. 起初看起来我们只是将开关/外壳移到了函数之外,这很重要,因为它允许不同的调用者具有不同的逻辑。 But watch for the third case. 但要注意第三种情况。

public void HandleData()
{
    switch (ReportItemOrder)
    {
        case SortOrder.Name: PrintReport(data, SortByName); break;
        case SortOrder.Type: PrintReport(data, SortByType); break;
        case SortOrder.Whatever: 
        Func<List<Item>, List<Item>> customSort = (items) => /* do something */;
        PrintReport(data, customSort);
    }
}

Delegates are commonly used to decouple classes and interfaces from each other. 委托通常用于将类和接口相互分离。

Here's a specific example. 这是一个具体的例子。 Suppose you had a UI class that was responsible for drawing a calendar, but you didn't want it to know exactly how to format the DateTime values into string. 假设您有一个负责绘制日历的UI类,但您不希望它确切地知道如何将DateTime值格式化为字符串。

You could define the class something like this: 您可以将类定义为:

public sealed class MyCalendarDrawer
{
    private readonly Func<DateTime, string> _dateFormatter;

    public MyCalendarDrawer(Func<DateTime, string> dateFormatter)
    {
        _dateFormatter = dateFormatter;
    }

    public void Draw()
    {
        // Do some work that involves displaying dates...

        DateTime date = DateTime.Now;

        string dateString = _dateFormatter(date);

        // Display dateString somehow.
    }
}

That way, MyCalendarDrawer doesn't need to know how to format the dates - it is told how to do it by being passed a delegate Func<DateTime, string> that it can call to do so. 这样, MyCalendarDrawer不需要知道如何格式化日期 - 它被告知如何通过传递它可以调用的委托Func<DateTime, string>来完成它。

Treating functions as first class types has its advantages. 将功能视为一流类型具有其优点。 It gives you functional programming possibilities. 它为您提供功能编程的可能性。

Take the classic case of "Event Handling" for example, you will certainly send a function pointer to another function as a call-back on occurance of an event. 以“事件处理”的经典案例为例,您肯定会将一个函数指针发送到另一个函数,作为事件发生时的回调。

Similarly, here is another hypothetical example 同样,这是另一个假设的例子

private void CallMeBack(out int type, Func<int> action)
{
   type = action();
}

Now I can supply any function to this, like CallMeBack(a, ()=>return 1); 现在我可以为此提供任何功能,如CallMeBack(a, ()=>return 1); and CallMeBack(a, ()=>return 2); CallMeBack(a, ()=>return 2);

You should read about Delegates. 你应该阅读有关代表的信息。 As example, delegates are useful to define a dynamic callback on a given method completion. 例如,委托对于在给定方法完成时定义动态回调很有用。

Pseudo-code example: 伪代码示例:

doSomething(); //your code
updateInterface(continueDoingSomething); //a generic method, passing a delegate

...

doAnythingElse();
updateInterface(continueDoingAnythingElse);

In this example, you could define a generic method "updateInterface" which, as a callback, calls a dynamic method passed in as a delegate. 在此示例中,您可以定义一个泛型方法“updateInterface”,它作为回调调用作为委托传入的动态方法。

If not using delegates, you would have to implement two (or more) different methods: 如果不使用委托,则必须实现两种(或更多种)不同的方法:

void updateInterfaceAndContinueDoingSomething(){}
void updateInterfaceAndContinueDoingAnythingElse(){}

Truth is, every single example where functions are passed to other functions can be expressed in term of objects implementing a given interface passed to functions. 事实上,函数传递给其他函数的每个例子都可以用实现传递给函数的给定接口的对象来表示。

In other words, there are no obvious reasons delegates are better than interfaces. 换句话说,没有明显的理由代表比接口更好。 Upcoming lambdas in Java are an example than you don't really need to be able to pass a function to another function to be able to have a concise syntax. Java中即将推出的lambdas就是一个例子,而不是你真的需要能够将一个函数传递给另一个函数才能拥有简洁的语法。

In yet another words, the ability to pass a function to another function is just a tool in your programmer's toolkit just as passing objectd to functions is. 换句话说,将函数传递给另一个函数的能力只是程序员工具箱中的一个工具,就像传递对象函数一样。 And while this is arguable which is better, one can have a language that doesn't support passing functions to functions at all - Java - and still be able to have the same expressiveness. 虽然这可以说是更好的,但是人们可以拥有一种语言,它不支持将函数传递给函数 - Java - 并且仍然能够具有相同的表达能力。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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