简体   繁体   English

请解释.NET代表

[英]Please Explain .NET Delegates

So I read MSDN and Stack Overflow. 所以我读了MSDN和Stack Overflow。 I understand what the Action Delegate does in general but it is not clicking no matter how many examples I do. 我理解Action Delegate一般会做什么,但不管我做了多少个例子都不点击。 In general, the same goes for the idea of delegates. 一般来说,代表的想法也是如此。 So here is my question. 所以这是我的问题。 When you have a function like this: 当你有这样的功能:

public GetCustomers(Action<IEnumerable<Customer>,Exception> callBack)
{
}

What is this, and what should I pass to it? 这是什么,我应该传递给它什么?

it expects a function that takes IEnumerable and Exception and returns void. 它需要一个采用IEnumerable和Exception并返回void的函数。

void SendExceptionToCustomers(IEnumerable<Customer> customers, Exception ex) {
   foreach(var customer in customers)
      customer.SendMessage(ex.Message);
}

GetCustomers(SendExceptionToCustomers);

btw, GetCustomers seems like a terrible name for this function -- it's asking for an action, so its more like DoSomethingToCustomers 顺便说一句,GetCustomers似乎是这个函数的一个可怕的名字 - 它要求一个动作,所以它更像是DoSomethingToCustomers

EDIT in response to comment 编辑回应评论


Ok Makes sense, So now why even bother with having a GetCustomer Function? Ok有道理,现在为什么还要为GetCustomer功能而烦恼呢? Can't I do that same thing with your function if i Just rename it GetCustomer? 如果我只是将它重命名为GetCustomer,我不能用你的功能做同样的事情吗?

Well, what's happening here is the caller can specify some action. 那么,这里发生的是调用者可以指定一些动作。 Suppose GetCustomers is implemented like this: 假设GetCustomers实现如下:

public void GetCustomers(Action<Enumerable<Customer>, Exception> handleError) {
    Customer[] customerlist =  GetCustomersFromDatabase();
    try {
        foreach(var c in customerList) 
            c.ProcessSomething()
    } catch (Exception e) {
        handleError(customerList, e);
    }
}

then you could call Getcustomers from somewhere on a commandline program, and pass it 然后你可以在命令行程序的某个地方调用Getcustomers,然后传递它

GetCustomers((list, exception) => { 
    Console.WriteLine("Encountered error processing the following customers");
    foreach(var customer in list) Console.WriteLine(customer.Name);
    Console.WriteLine(exception.Message);
}); 

while you could call GetCustomers from a remote application, for example, and pass it 例如,您可以从远程应用程序调用GetCustomers,然后传递它

Getcustomers((list, exception) => { 
    // code that emails me the exception message and customer list
})


Also, Slak's comment suggests another reason for delegate parameter -- GetCustomers does retrieve the customers, but asynchronously. 此外,Slak的评论提出了委托参数的另一个原因 - GetCustomers确实检索客户,但是异步。 Whenever it is done retrieving the customers, it calls the function you give it with either the customerlist or an exception, if an exception occurred. 每当检索到客户时,如果发生异常,它会使用客户列表或异常调用您提供的功能。

A delegate is a class that points to one or more functions. 委托是指向一个或多个功能的类。 A delegate instance can be invoked, which will call the function(s) that it points to. 可以调用委托实例,该实例将调用它指向的函数。

In your case, the GetCustomers function takes a second function as a parameter. 在您的情况下, GetCustomers函数将第二个函数作为参数。

The second function must take two parameters of type IEnumerable<Customer> and Exception . 第二个函数必须采用IEnumerable<Customer>Exception类型的两个参数。

To call GetCustomers , you need to make a second function for it to call, then pass it a delegate containing the second function. 要调用GetCustomers ,您需要为它调用第二个函数,然后传递一个包含第二个函数的委托。

For example: 例如:

static void GetCustomersCallback(IEnumerable<Customer> customers, Exception ex) {
    //Do something...
}

//Elsewhere:
GetCustomers(new Action<IEnumerable<Customer>,Exception>(GetCustomersCallback));

This call creates a new delegate instance that points to the GetCustomersCallback function, and passes that delegate to the GetCustomers function. 此调用创建一个指向GetCustomersCallback函数的新委托实例,并将该委托传递给GetCustomers函数。 GetCustomers will presumably call the callback after the customers finish loading, and will pass the loaded customers as a parameter. GetCustomers可能会在客户完成加载后调用回调,并将加载的客户作为参数传递。
You can also leave out the delegate instantiation and pass the function directly: 您也可以省略委托实例化并直接传递函数:

GetCustomers(GetCustomersCallback);

you can call it with a lambda 你可以用lambda来调用它

GetCustomers((cust, ex) => {
    //do something here}
);

It's just an updated version of C's function pointers with the possibility of it being tied to an object instance if it's a non-static object method pointer (C++ called them method pointers when they added objects and function pointers together). 它只是C函数指针的更新版本,如果它是非静态对象方法指针(C ++在将对象和函数指针组合在一起时称为方法指针),则可能将其绑定到对象实例。

The type signature can be made generic using C#'s generic's features. 使用C#的通用功能可以使类型签名成为通用的。

All the generics stuff is just templatizing the signature. 所有仿制药都只是模仿签名。

The name delegate is poorly chosen (unless you think of all of our apps being driven by frameworks). 名称委托选择不当(除非您认为我们的所有应用程序都是由框架驱动的)。 Because the use is not always "to delegate". 因为使用并不总是“委托”。 Often times it's the code you have delegated some responsibility to (an iterator, say) which calls the "delegate" you previously sent in. Which is why you often see the term callback. 通常情况下,您委托的代码(一个迭代器,比如说)调用您之前发送的“委托”。这就是您经常看到术语回调的原因。

Callbacks have traditionally been used in frameworks for your application code to be called in the middle of a loop or when a particular event happens. 回调传统上一直用在框架中,以便在循环中或特定事件发生时调用应用程序代码。 It allows you to get your code to happen in the middle of other code - in fact, it's just about the only way within a thread. 它允许您让代码在其他代码中间发生 - 实际上,它只是线程中的唯一方法。

Obviously, .NET event handlers are delegates being called by the framework at appropriate times, and you can accept delegates in your functions and call them appropriate to allow you to make your code somewhat generic/reusable/organized. 显然,.NET事件处理程序是框架在适当的时候调用的委托,您可以接受函数中的委托并调用它们,以使您的代码具有某种通用性/可重用性/组织性。

Simply? 只是? Function pointers 函数指针

You would pass it a void method that takes an IEnumerable and an Exception as parameters... 你会传递一个void方法,它将IEnumerable和Exception作为参数...

Say you have this method: 说你有这个方法:

public void DoSomeStuffWithCustomers(
  IEnumerable<Customer> customers, Exception exception)
{     
}

You would call the GetCustomers method like this: 您可以像这样调用GetCustomers方法:

GetCustomers(DoSomeStuffWithCustomers);

They confused the hell out of me until I read: 在我读到之前,他们把我弄糊涂了:

  1. Andrew Troelsen's explanation of them in Pro C# 2008 and the .Net 3.5 Platform Andrew Troelsen在Pro C#2008和.Net 3.5平台中对它们的解释
  2. The chapter on the Observer pattern in Head First Design Patterns 头部优先设计模式中观察者模式的章节

That second book is about java, and doesn't mention delegates, but it explains well a problem delegates help solve: communication between classes. 第二本书是关于java的,并没有提到委托,但它解释了委托帮助解决的问题:类之间的通信。

有关DotNet代表和事件的详细信息,请参阅链接: http//www.codeproject.com/KB/cs/Delegate_To_Event_in_CS.aspx

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

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