有人可以将代表的内容分解为一个简单,简洁和简洁的解释,其中包含目的和一般好处吗?我试图绕过这个并且它只是没有陷入其中。
答案 0 :(得分:30)
我有一个功能:
public long GiveMeTwoTimesTwo()
{
return 2 * 2;
}
这个功能很糟糕。如果我想要3 * 3怎么办?
public long GiveMeThreeTimesThree()
{
return 3 * 3;
}
打字太多了。我很懒!
public long SquareOf(int n)
{
return n * n;
}
我的SquareOf
功能并不关心n
是什么。对于传入的任何n
,它都能正常运行。它并不确切知道n
的确切数字,但确实知道n
是一个整数。您无法将"Haha not an integer"
传递给SquareOf
。
这是另一个功能:
public void DoSomethingRad()
{
int x = 4;
long y = SquareOf(x);
Console.WriteLine(y);
}
与其名称相反,DoSomethingRad实际上并没有做任何事情。但是,它确实写了SquareOf(4)16,我们可以把它改成不那么无聊吗?
public void DoSomethingRad(int numberToSquare)
{
long y = SquareOf(numberToSquare);
Console.WriteLine(y);
}
DoSomethingRad
显然仍然很失败。但至少现在我们可以传入一个数字到正方形,所以每次都不会写入16。 (它会写1,或4,或9,或16,或...... zzzz仍然有点无聊)。
如果有办法改变传入的数字,那就太好了。也许我们不想把它放在一边;也许我们想要将它立方体化,或者从69中减去它(从我脑中随机选择的数字)。
在进一步检查时,似乎SquareOf
关注DoSomethingRad
的唯一部分是我们可以给它一个整数(numberToSquare
)并且它给我们一个{ {1}}(因为我们将其返回值放在long
中且y
为y
)。
long
查看public long CubeOf(int n)
{
return n * n * n;
}
public void DoSomethingLeet(int numberToSquare)
{
long y = CubeOf(numberToSquare);
Console.WriteLine(y);
}
与DoSomethingLeet
的相似程度?如果只有传递行为的方式(DoSomethingRad
)而不仅仅是数据(DoX()
)...
所以现在如果我们想要写一个数字的正方形,我们可以int n
,如果我们想写一个数字的立方体,我们可以DoSomethingRad
。因此,如果我们要写出从69减去的数字,我们是否必须制作另一种方法DoSomethingLeet
?不,因为打字太多了(更重要的是,它阻碍了我们通过改变程序的一个方面来改变有趣行为的能力)。
所以我们到达:
DoSomethingCool
我们可以通过写这个来调用这个方法:
public long Radlicious(int doSomethingToMe, Func<int, long> doSomething)
{
long y = doSomething(doSomethingToMe);
Console.WriteLine(y);
}
Radlicious(77, SquareOf);
是一种特殊的代表。它存储接受整数并吐出Func<int, long>
的行为。我们不确定它指向的方法与我们传递的任何给定整数有关;我们所知道的是,无论发生什么,我们都会得到一个long
。
我们不必向long
提供任何参数,因为SquareOf
描述了行为,而不是数据。致电Func<int, long>
只会给予Radlicious Radlicious(77, SquareOf)
的一般行为(“我拿一个数字并返回其正方形”),而不是SquareOf
对任何特定的行为整数。
现在,如果你已经理解了我所说的话,那么你已经有了一个人,因为我自己并没有真正得到这些东西。
* END ANSWER,开始痴迷IDIOCY *
我的意思是,似乎SquareOf
可能被认为是非常无聊的行为:
int
尽管如此,数据与行为之间的界限似乎模糊不清,通常认为数据只是无聊的行为。
当然,人们可以想象超级“有趣”的行为,它会采用各种抽象参数,但需要大量信息才能调用它。如果它要求我们提供它将为我们编译和运行的源代码怎么办?
那么,我们的抽象似乎已经让我们一路回到原点。我们的行为如此抽象,需要我们程序的完整源代码来确定它将要做什么。这是完全不确定的行为:该函数可以执行任何,但必须提供所有以确定它的作用。另一方面,完全确定的行为(例如static int Nine()
{
return 9;
}
)不需要任何其他信息,但除了返回Nine()
之外无法执行任何操作。
那又怎样?我不知道。
答案 1 :(得分:21)
用最简单的术语来说,它本质上是指向方法的指针。
您可以拥有一个包含委托类型的变量(就像您拥有一个可以保存int类型的int变量一样)。您只需像调用函数一样调用变量,就可以执行委托所指向的方法。
这使您可以像拥有可变数据一样拥有变量函数。您的对象可以接受来自其他对象的委托并调用它们,而无需自己定义所有可能的函数。
当您希望对象根据用户指定的条件执行操作时,这非常方便。例如,根据用户定义的true / false表达式过滤列表。您可以让用户指定委托函数以用作过滤器来评估每个列表项。
答案 2 :(得分:3)
答案 3 :(得分:3)
有趣的是,没有人提到授权的一个主要好处 - 当你意识到继承不是一个神奇的子弹并且通常会产生比它解决的更多问题时,它更可取于子类化。它是许多设计模式的基础,最着名的是策略模式。
答案 4 :(得分:2)
委托实例是对方法的引用。它们有用的原因是您可以创建一个与特定类型实例上的特定方法绑定的委托。委托实例允许您在该特定实例上调用该方法,即使您将调用该方法的对象已离开您的词法范围。
像这样的委托实例最常见的用途是在语言层面支持callbacks的概念。
答案 5 :(得分:2)
它只是引用一种方法。它们在使用交叉线程时非常有用。
以下是我的代码中的一个示例。
//Start our advertisiment thread
rotator = new Thread(initRotate);
rotator.Priority = ThreadPriority.Lowest;
rotator.Start();
#region Ad Rotation
private delegate void ad();
private void initRotate()
{
ad ad = new ad(adHelper);
while (true)
{
this.Invoke(ad);
Thread.Sleep(30000);
}
}
private void adHelper()
{
List<string> tmp = Lobby.AdRotator.RotateAd();
picBanner.ImageLocation = @tmp[0].ToString();
picBanner.Tag = tmp[1].ToString();
}
#endregion
如果您没有使用委托,则无法进行交叉传输并调用Lobby.AdRotator函数。
答案 6 :(得分:1)
就像其他人所说的那样,委托是对函数的引用。一个更有益的用途(IMO)是事件。注册事件时,您需要为要调用的事件注册一个函数,并且委托非常适合此任务。
答案 7 :(得分:1)
在最基本的术语中,委托只是一个包含(引用)函数的变量。代理很有用,因为它们允许您将函数作为变量传递,而不必担心函数实际来自何处。
当然,重要的是要注意,当函数被捆绑在一个变量中时,它不会被复制;它只是受到参考的约束。例如:
class Foo
{
public string Bar
{
get;
set;
}
public void Baz()
{
Console.WriteLine(Bar);
}
}
Foo foo = new Foo();
Action someDelegate = foo.Baz;
// Produces "Hello, world".
foo.Bar = "Hello, world";
someDelegate();
答案 8 :(得分:1)
在大多数最简单的术语中,执行方法的责任委托给另一个对象。说一些国家的总统去世,美国总统应该出席哀悼的葬礼。如果美国总统无法前往,他将把这一责任委托给副总统或国务秘书。
代码也一样。委托是一种类型,它是一个能够执行该方法的对象。
例如。
Class Person
{
public string GetPersonName(Person person)
{
return person.FirstName + person.LastName;
}
//Calling the method without the use of delegate
public void PrintName()
{
Console.WriteLine(GetPersonName(this));
}
//using delegate
//Declare delegate which matches the methods signature
public delegate string personNameDelegate(Person person);
public void PrintNameUsingDelegate()
{
//instantiate
personNameDelegate = new personNameDelegate(GetPersonName);
//invoke
personNameDelegate(this);
}
}
使用委托对象personNameDelegate调用GetPersonName方法。 或者,我们可以使用PrintNameUsingDelegate方法将委托作为参数。
public void PrintNameUsingDelegate(personNameDelegate pnd, Person person)
{
pnd(person);
}
优点是如果有人想要将名称打印为lastname_firstname,他/她只需将该方法包装在personNameDelegate中并传递给此函数。无需进一步更改代码。
代表在
中特别重要答案 9 :(得分:0)
如果您要将某个任务委派给某人,该代表将是接收该工作的人。
在编程中,它是对实际知道如何做某事的代码块的引用。通常这是指向处理某个项目的函数或方法的指针。
答案 10 :(得分:0)
用绝对最简单的术语我可以想到的是:一个代表将把工作的负担强加到一个非常知道该做什么的班级手中。把它想象成一个孩子,不想长大成为他的大哥,但仍然需要他的指导和命令。他没有继承他兄弟的所有方法(即子类化),而是让他的兄弟做工作或者小弟弟做了一些需要大哥采取行动的事情。当你进入协议的范围时,大哥定义了绝对必要的内容,或者他可以灵活地选择你想让他在某些事件中做什么(即Objective-C中概述的非正式和正式协议)。
这个概念的绝对好处是你不需要创建一个子类。如果你想要一些东西排成一行,在事件发生时按照命令,委托允许一个开发的类握住它并在必要时发出命令。