【问题标题】:How does the keyword delegate work compared to creating a delegate与创建委托相比,关键字委托如何工作
【发布时间】:2012-12-10 14:17:24
【问题描述】:

我正在慢慢了解委托,因为委托的签名也必须与它所委托的方法的签名相匹配。

但是,请查看以下代码。

public static void Save()
{
    ThreadStart threadStart = delegate
    {
        SaveToDatabase();
    };
    new Thread(threadStart).Start();
}

private static void SaveToDatabase() { }

我现在被难住了,因为代表返回 void(这就是 SaveToDatabase() 的意思)但是,它显然返回了 ThreadStart... 或者是吗?

如果我要编写自己的委托,我将不知道如何实现这一点,因为委托必须是 void 才能匹配 SaveToDatabase() 的返回类型。但它不可能;它的类型是ThreadStart!

我的问题是,我是否完全误解了,或者这是否通过一些 .NET 诡计而成为可能?如果我想编写此方法但要创建自己的委托,我会怎么做?

【问题讨论】:

  • 为什么不ThreadStart threadStart=new ThreadStart(SaveToDatabase);
  • 我认为没有返回任何内容,因为没有 return 关键字。我认为正在创建一个新的thread,它将执行委托所指向的方法。
  • @Some1.Kill.The.DJ - 从长远来看,它实际上会采用一些参数。
  • 这是一个匿名方法,与委托关系不大。他们有点老派,这些天你会使用 lambda 表达式。 msdn.microsoft.com/en-us/library/0yw3tz5k%28v=VS.80%29.aspx
  • 是的,具有讽刺意味的是,我可以用 Lamda's 做到这一点(我开始使用 .net 3.5 / 4.0 学习,但我正在使用 2.0 的项目)!

标签: c# delegates


【解决方案1】:

“代表”这个词有点被滥用了。使用类和对象更容易。 “类”就像一个对象的蓝图。 “对象”是内存中的一个实际实例,它遵循类的蓝图。

对于代表,我们使用相同的词,因此我怀疑您的困惑。考虑以下代码:

class Main
{
    public delegate int DelegateType(string x);
    public int SomeFunction(string y) { return int.Parse(y)*2; }
    public void Main()
    {
        DelegateType delegateInstance = null;
        delegateInstance = SomeFunction;
        int z = delegateInstance("21");
        Console.WriteLine(z);
    }
}

此代码输出“42”。

DelegateType 是委托的类型。就像类是对象的蓝图一样,委托是函数的蓝图。

所以稍后我们创建一个名为delegateInstance 的变量,其类型为DelegateType。对于该变量,我们可以分配 ANY 函数,该函数接受单个字符串参数并返回一个整数。请注意,我们分配了函数本身,而不是该函数的结果。就像delegateInstance 变量现在是该函数的同义词。事实上,正如后面一行所展示的,我们现在可以使用delegateInstance 来调用该函数!就好像delegateInstance 本身就是一个函数一样。但是,由于它是可变的,我们也可以做我们通常对变量所做的所有相同的事情——比如将它们作为参数传递给其他函数,甚至从其他函数返回(一个返回函数的函数!绕着你的脑袋!)

好的,让我们看看让你感到困惑的代码。

public static void Save()
{
    ThreadStart threadStart = delegate
    {
        SaveToDatabase();
    };
    new Thread(threadStart).Start();
}

private static void SaveToDatabase() { }

首先要注意的是您使用了anonymous delegate。该术语的另一个误用。编译后,结果如下:

public static void Save()
{
    ThreadStart threadStart;
    threadStart = __ASDASDASD6546549871;
    var tmp = new Thread(threadStart);
    tmp.Start();
}

private static void SaveToDatabase() { }

private void __ASDASDASD6546549871()
{
    SaveToDatabase();
}

请注意,您的匿名函数实际上已转换为具有随机名称的完全常规函数,然后将该函数分配给 threadStart 变量。

所以现在这就像上面的例子一样。只需将DelegateType 替换为ThreadStart,将delegateInstance 替换为threadStart,将SomeFunction 替换为__ASDASDASD6546549871

现在有意义吗?

【讨论】:

  • 这真的很好 - 非常感谢您花时间解释这一点,它帮助很大。谢谢。
【解决方案2】:

我现在被难住了,因为委托返回 void(这就是 SaveToDatabase() 的含义)但是,它显然返回了一个 ThreadStart... 或者是吗?

如果我要纠正我自己的委托,我将不知道如何实现这一点,因为委托必须是 void 才能匹配 SaveToDatabase() 的返回类型,但不能是因为它是类型线程开始!

ThreadStart 被定义为委托。其实是这样定义的

public delegate void ThreadStart();

所以您的代码没有返回委托或ThreadStart。它只是定义一个与ThreadStart 委托定义匹配的函数。 Thread 构造函数需要一个 ThreadStart 委托,您已将其定义为变量 threadStart,它指向 SaveToDatabase 函数。

我倾向于将委托视为旧的 C++ 术语“函数指针”。委托允许我们指定应该将哪种函数(参数和返回类型)作为参数传递给另一个函数。

我的问题是,我是否完全误解了,或者这是否通过一些 .NET 诡计而成为可能?如果我想编写此方法但要创建自己的委托,我会怎么做?

我想你可能误会了。但要具体回答这个问题,您将编写的方法只需要匹配委托类型指定的定义,在本例中为 ThreadStart。该方法定义必须返回 void 并且不接受任何参数。您的 SaveToDatabase 方法与此委托类型匹配,因此是要创建的正确委托方法。

【讨论】:

  • 只是一个返回void的方法。 ThreadStart() 构造函数代码是一种构造委托指针代码的方法。您也可以轻松地将与 ThreadStart 委托类型匹配的方法名称传递给 Thread 构造函数。
【解决方案3】:

当你要运行一个被管理的子进程时,要执行的方法由ThreadStartParameterizedThreadStart表示,但SaveToDatabasevoid,它将以void签名执行,而不是 ThreadStart 类型。

来自 MSDN 的示例:

class Test
{
    static void Main() 
    {
        // To start a thread using a static thread procedure, use the
        // class name and method name when you create the ThreadStart
        // delegate. Beginning in version 2.0 of the .NET Framework,
        // it is not necessary to create a delegate explicityly. 
        // Specify the name of the method in the Thread constructor, 
        // and the compiler selects the correct delegate. For example:
        //
        // Thread newThread = new Thread(Work.DoWork);
        //
        ThreadStart threadDelegate = new ThreadStart(Work.DoWork);
        Thread newThread = new Thread(threadDelegate);
        newThread.Start();

        // To start a thread using an instance method for the thread 
        // procedure, use the instance variable and method name when 
        // you create the ThreadStart delegate. Beginning in version
        // 2.0 of the .NET Framework, the explicit delegate is not
        // required.
        //
        Work w = new Work();
        w.Data = 42;
        threadDelegate = new ThreadStart(w.DoMoreWork);
        newThread = new Thread(threadDelegate);
        newThread.Start();
    }
}

class Work 
{
    public static void DoWork() 
    {
        Console.WriteLine("Static thread procedure."); 
    }
    public int Data;
    public void DoMoreWork() 
    {
        Console.WriteLine("Instance thread procedure. Data={0}", Data); 
    }
}

【讨论】:

  • 那么,如果我创建了自己的委托,它仍然是 void 类型吗?
  • 您可以创建自己的函数。 SaveToDatabase、SaveToDatabase2、SaveAgainToDatabase,如果这些方法都是void,你可以将它们传递给ThreadStart构造函数
  • 检查我发布的 msdn 中的代码示例。它有 DoWork In other class with void Signature
  • 我看过那个例子,但是从来没有使用过“代表”这个词,因此,我无法想象代表是如何被消费的。
  • Thread 使用他的 ThreadStart 委托,因为你必须在构造函数中传递这个 Delegate 类型。它就像一个接收 int 参数的函数,你不能传递一个字符串。如果您想了解委托的工作原理,我建议您使用委托创建自定义事件
【解决方案4】:

来自 MSDN

委托是一种引用方法的类型。一旦为委托分配了一个方法,它的行为就与该方法完全一样。委托方法可以像任何其他方法一样使用,带有参数和返回值,如下例所示:

public delegate int PerformCalculation(int x, int y);

所以委托的返回类型将匹配它所委托的方法的返回类型。

任何与委托签名匹配的方法,包括返回类型和参数,都可以分配给委托。这使得以编程方式更改方法调用以及将新代码插入现有类成为可能。只要知道委托的签名,就可以分配自己的委托方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 2011-01-12
    • 1970-01-01
    • 2010-09-22
    • 2013-11-19
    相关资源
    最近更新 更多