所以我对C#中的代表感到有点困惑....他们做了什么以及它们如何有用?我已经阅读了一些教程,我并没有真正得到它们应该做的事情(每个人都将它们与C中的函数指针联系起来,而我从未在C中编程)。
那么...代表们做了什么?我应该使用它们的场景是什么?那我怎么用呢?
答案 0 :(得分:6)
其他答案都很好,但这是考虑可能会有所帮助的代表的另一种方式。想象一下,委托只不过是一个界面。当你看到:
delegate void Action();
认为:
interface IAction
{
void Invoke();
}
当你看到:
Action myAction = foo.Bar;
认为:
class FooBarAction : IAction
{
public Foo Receiver { get; private set; }
public FooBarAction(Foo foo)
{
this.Receiver = foo;
}
public void Invoke()
{
this.Receiver.Bar();
}
}
...
IAction myAction = new FooBarAction(foo);
当你看到
myAction();
认为
myAction.Invoke();
构建什么类型的实际细节有点不同,但从根本上说这就是正在发生的事情。委托只是一个带有一个名为Invoke的方法的对象,当你调用该方法时,它会代表你的某个其他对象调用其他方法。这就是为什么它被称为“委托” - 因为它委托调用另一个对象的另一个方法。
答案 1 :(得分:4)
委托类似于表示方法调用的对象。可以使用它们的一种有用方法是作为回调。例如,假设您有一个执行异步操作的方法,并且您希望调用者能够在完成后指定他们想要发生的事情(Action
是一种委托):
public void DoSomething(Action whatToDoWhenDone)
{
// Your code
// See how the delegate is called like a method
whatToDoWhenDone();
}
DoSomething
的用户现在可以将回调指定为参数:
public void AnotherMethod()
{
DoSomething(ShowSuccess); // ShowSuccess will be called when done
}
public void ShowSuccess()
{
Console.WriteLine("Success!");
}
您还可以使用lamba表达式作为编写委托的较短方式:
public void AnotherMethod()
{
DoSomething(() => Console.WriteLine("Success!"));
// Also DoSomething(delegate() { Console.WriteLine("Success!"); });
}
回调远不是代表的唯一用例。希望这能够向您展示他们的一些能力:能够将代码执行作为变量。
答案 2 :(得分:1)
代理允许您将函数视为任何其他变量。委托类型定义函数的签名,即函数返回的内容,以及它所需的参数的数量和类型:
// This is the delegate for a function that takes a string and returns a string.
// It can also be written using the framework-provided Generic delegate Func, as
// Func<String, String>
delegate String StringToStringDelegate(String input);
您可以定义此类型的变量,并将其分配给现有方法。我使用泛型作为示例,因为这是自2.0以来在.net中更常见的用法:
String Reverse(String input) {
return input.Reverse();
}
Func<String, String> someStringMethod = new Func<String, String>(Reverse);
// Prints "cba":
Console.WriteLine(someStringMethod("abc"));
你也可以这样传递函数:
String Reverse(String input) {
return input.Reverse();
}
String UpperCase(String input) {
return input.ToUpper();
}
String DoSomethingToABC(Func<String, String> inputFunction) {
return inputFunction("abc");
}
var someStringMethod = new Func<String, String>(Reverse);
// Prints "cba":
Console.WriteLine(DoSomethingToABC(someStringMethod));
var someOtherStringMethod = new Func<String, String>(UpperCase);
// Prints "ABC":
Console.WriteLine(DoSomethingToABC(someOtherStringMethod));
答案 3 :(得分:0)
在大型应用程序中,基于某些条件或其他内容,通常需要应用程序的其他部分。委托指定要调用的方法的地址。以简单的方式,普通事件处理程序实现内层中的委托。
答案 4 :(得分:0)
过度简化的答案是委托基本上是代码块的“指针”,好处是你可以通过将代码块分配给变量来将这段代码传递给其他函数。
人们将委托与C函数指针联系起来的原因是因为这实质上就是委托的全部内容,即:方法的指针。
举个例子:
public void DoSomething(Action yourCodeBlock)
{
yourCodeBlock();
}
public void CallingMethod()
{
this.DoSomething(
{
... statements
});
this.DoSomething(
{
... other statements
});
}
有很多方法可以调用代理,因为所有教程都会向您展示。关键是,它允许您以这样一种方式“委派”功能,即您可以调用方法而不必知道它们如何工作,而只是相信它们将被处理。换句话说,我可能会创建一个实现“DoSomething()”函数的类,但我可以将其留给其他人来决定DoSomething()稍后会做什么。
我希望有所帮助。 : - )
答案 5 :(得分:0)
代理是一种在长时间运行的操作完成或事件发生时回调代码的方法。例如,您将委托传递给在后台异步下载文件的方法。下载完成后,将调用您的委托方法,然后可以执行某些操作,例如处理文件的内容。
事件处理程序是一种特殊类型的委托。例如,事件处理程序委托可以响应鼠标单击或按键等事件。事件是迄今为止最常见的代理类型。事实上,您通常会在C#代码中看到事件关键字的使用频率远高于委托关键字。
答案 6 :(得分:0)
您可以将其视为可以存储对函数的引用的类型。这样你就可以将函数存储在一个变量中,这样你可以像以后任何函数一样调用它。
如,
public delegate void AnEmptyVoidFunction();
这将创建一个名为AnEmptyVoidFunction
的委托类型,它可用于存储对返回void且没有参数的函数的引用。
然后,您可以存储对具有该签名的函数的引用。
public static void SomeMethod() { }
public static int ADifferentMethod(int someArg) { return someArg; }
AnEmptyVoidFunction func1 = new AnEmptyVoidFunction(SomeMethod);
// or leave out the constructor call to let the compiler figure it out
AnEmptyVoidFunction func2 = SomeMethod;
// note that the above only works if it is a function defined
// within a class, it doesn't work with other delegates
//AnEmptyVoidFunction func3 = new AnEmptyVoidFunction(ADifferentMethod);
// error wrong function type
它不仅可以存储声明的函数,还可以存储匿名函数(即lambdas或匿名代理)
// storing a lambda function (C#3 and up)
AnEmptyVoidFunction func4 = () => { };
// storing an anonymous delegate (C#2)
AnEmptyVoidFunction func5 = delegate() { };
要调用这些委托,您可以像调用任何其他函数一样调用它们。虽然它是变量,但您可能需要事先检查它是否为null
。
AnEmptyVoidFunction func1 = () =>
{
Console.WriteLine("Hello World");
};
func1(); // "Hello World"
AnEmptyVoidFunction func2 = null;
func2(); // NullReferenceException
public static void CallIt(AnEmptyDelegate func)
{
// check first if it is not null
if (func != null)
{
func();
}
}
只要您需要传递要调用的方法,就可以使用它们。几乎与您传递对象实例的方式相同,这样您就可以按照自己的意愿行事。代表的典型用例是在声明事件时。我已经写了another answer来描述模式,所以你可以看看它有关如何编写这些模式的更多信息。