与创建委托相比,关键字委托如何工作

时间:2012-12-10 14:17:25

标签: c# delegates

我正在慢慢地围绕代表,因为委托的签名必须与委托方法的签名相匹配。

但是,请查看以下代码。

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

private static void SaveToDatabase() { }

我现在很难过,因为委托会返回void(因为那是SaveToDatabase())但是,它显然会返回ThreadStart ......或者是它?

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

我的问题是,我是否完全误解了或者是否因为一些.NET技巧而成为可能?如果我想写这个方法但是创建我自己的委托,我会怎么做?

4 个答案:

答案 0 :(得分:5)

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

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

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

现在有意义吗?

答案 1 :(得分:4)

  

我现在感到困惑,因为委托返回void(因为这就是SaveToDatabase())但是,它显然返回了一个ThreadStart ......或者是它?

     

如果我要修改自己的委托,我不知道如何实现这一点,因为委托必须是无效的,以匹配SaveToDatabase()的返回类型,但不能因为它是类型的ThreadStart!

ThreadStart被定义为委托。实际上,它被定义为

public delegate void ThreadStart();

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

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

  

我的问题是,我是否完全误解了或者是否因为一些.NET技巧而成为可能?如果我想写这个方法但是创建我自己的委托,我会怎么做?

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

答案 2 :(得分:2)

当您要运行管理的子流程时,将要执行的方法由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); 
    }
}

答案 3 :(得分:2)

来自MSDN

  

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

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

因此委托的返回类型将与它委派的方法的返回类型相匹配。

  

可以将与委托签名匹配的任何方法(包括返回类型和参数)分配给委托。这使得可以以编程方式更改方法调用,并将新代码插入现有类中。只要您知道代理人的签名,就可以指定自己的委托方法。