我想我将 C# 中委托的概念理解为指向方法的指针,但我找不到任何好的例子来说明在哪里使用它们是个好主意。有哪些例子对于代表来说更优雅/更好,或者不能使用其他方法解决?
12 回答
.NET 1.0 代表:
this.myButton.Click += new EventHandler(this.MyMethod);
.NET 2.0 代表:
this.myOtherButton.Click += delegate {
var res = PerformSomeAction();
if(res > 5)
PerformSomeOtherAction();
};
它们看起来非常有用。怎么样:
new Thread(new ThreadStart(delegate {
// do some worker-thread processing
})).Start();
我主要使用简单的异步编程。使用委托开始一个方法 Begin... 如果你想开火然后忘记,方法真的很容易。
当接口不可用时,委托也可以像接口一样使用。例如,从 COM 类、外部 .Net 类等调用方法。
你说的代表到底是什么意思?以下是可以使用它们的两种方式:
void Foo(Func<int, string> f) {
//do stuff
string s = f(42);
// do more stuff
}
和
void Bar() {
Func<int, string> f = delegate(i) { return i.ToString(); }
//do stuff
string s = f(42);
// do more stuff
}
第二个要点是您可以动态声明新函数,作为委托。这可以在很大程度上被 lambda 表达式所取代,并且在您想要将一小段逻辑 1) 传递给另一个函数或 2) 只是重复执行时很有用。LINQ 就是一个很好的例子。每个 LINQ 函数都将 lambda 表达式作为其参数,指定行为。例如,如果你有一个List<int> l
thenl.Select(x=>(x.ToString())
将对列表中的每个元素调用 ToString()。我写的 lambda 表达式是作为委托实现的。
第一个案例展示了如何实现 Select。您将委托作为参数,然后在需要时调用它。这允许调用者自定义函数的行为。再次以 Select() 为例,函数本身保证了你传递给它的委托会在列表中的每个元素上被调用,并且每个元素的输出都会被返回。该代表实际做什么取决于您。这使它成为一个非常灵活和通用的功能。
当然,它们也用于订阅事件。简而言之,委托允许您引用函数,将它们用作函数调用中的参数,将它们分配给变量以及您喜欢做的任何其他事情。
事件是最明显的例子。比较观察者模式是如何在 Java(接口)和 C#(委托)中实现的。
此外,许多新的 C# 3 功能(例如 lambda 表达式)都基于委托,并进一步简化了它们的使用。
例如在多线程应用程序中。如果您希望多个线程使用某些控制,您应该使用委托。抱歉,代码在 VisualBasic 中。
首先你声明一个委托
Private Delegate Sub ButtonInvoke(ByVal enabled As Boolean)
编写一个函数以从多个线程启用/禁用按钮
Private Sub enable_button(ByVal enabled As Boolean)
If Me.ButtonConnect.InvokeRequired Then
Dim del As New ButtonInvoke(AddressOf enable_button)
Me.ButtonConnect.Invoke(del, New Object() {enabled})
Else
ButtonConnect.Enabled = enabled
End If
End Sub
我一直将它们与 LINQ 一起使用,尤其是 lambda 表达式,以提供一个函数来评估条件或返回选择。还可以使用它们来提供一个功能,该功能将比较两个项目以进行排序。后者对于默认排序可能合适也可能不合适的通用集合很重要。
var query = collection.Where( c => c.Kind == ChosenKind )
.Select( c => new { Name = c.Name, Value = c.Value } )
.OrderBy( (a,b) => a.Name.CompareTo( b.Name ) );
委托的好处之一是异步执行。
当您异步调用一个方法时,您不知道它何时完成执行,因此您需要将一个委托传递给该方法,该委托指向另一个方法,该方法将在第一个方法完成执行时调用。在第二种方法中,您可以编写一些代码来通知您执行已完成。
从技术上讲,委托是一种引用类型,用于封装具有特定签名和返回类型的方法
其他一些评论触及了异步世界......但无论如何我都会发表评论,因为我最喜欢这样做的“味道”已经提到:
ThreadPool.QueueUserWorkItem(delegate
{
// This code will run on it's own thread!
});
此外,代表的一个重要原因是“回调”。假设我做了一些功能(异步),并且您希望我调用一些方法(例如“AlertWhenDone”)......您可以将“委托”传递给您的方法,如下所示:
TimmysSpecialClass.DoSomethingCool(this.AlertWhenDone);
除了它们在事件中的角色之外,如果您使用过 winforms 或 asp.net,您可能会熟悉委托,委托对于使类更灵活(例如它们在 LINQ 中的使用方式)很有用。
“查找”事物的灵活性非常普遍。你有一个东西的集合,你想提供一种查找东西的方法。您现在可以允许调用者提供算法,以便他们可以搜索您的集合,但他们认为合适,而不是猜测某人可能想要查找的每种方式。
这是一个简单的代码示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Delegates
{
class Program
{
static void Main(string[] args)
{
Collection coll = new Collection(5);
coll[0] = "This";
coll[1] = "is";
coll[2] = "a";
coll[3] = "test";
var result = coll.Find(x => x == "is");
Console.WriteLine(result);
result = coll.Find(x => x.StartsWith("te"));
Console.WriteLine(result);
}
}
public class Collection
{
string[] _Items;
public delegate bool FindDelegate(string FindParam);
public Collection(int Size)
{
_Items = new string[Size];
}
public string this[int i]
{
get { return _Items[i]; }
set { _Items[i] = value; }
}
public string Find(FindDelegate findDelegate)
{
foreach (string s in _Items)
{
if (findDelegate(s))
return s;
}
return null;
}
}
}
输出
是
测试
确实没有什么可以用其他方法解决的,但它们提供了一个更优雅的解决方案。
使用委托,任何函数都可以使用,只要它具有所需的参数。
另一种方法通常是在程序中使用一种自定义构建的事件系统,从而创造额外的工作和更多的区域让错误潜入
在处理对数据库的外部调用时使用委托是否有优势?
例如可以编码 A :
static void Main(string[] args) {
DatabaseCode("test");
}
public void DatabaseCode(string arg) {
.... code here ...
}
在代码 B 中进行改进:
static void Main(string[] args) {
DatabaseCodeDelegate slave = DatabaseCode;
slave ("test");
}
public void DatabaseCode(string arg) {
.... code here ...
}
public delegate void DatabaseCodeDelegate(string arg);
这似乎是主观的,但是一个存在强烈冲突观点的领域?