Action与委托实例化和可访问性之间的区别

时间:2017-07-19 21:08:23

标签: c# delegates action

为什么MyDeler"静态",因为我可以通过类名访问MyDeler,但我不能说明公共"静态"委托void MyDeler(),也不能通过MyClass实例访问d,就像在新的MyClass.d()中一样?

此外,为什么我必须新建MyClass才能使用MyVoidAction?

见下面的代码:

using System;

public class MyClass
{
    public delegate void MyDeler();
    public Action MyVoidAction;
}

class MainClass
{
    static void Main()
    {
        MyClass.MyDeler d = () => Console.WriteLine("my deler");
        d();
        // MyClass.MyVoidAction mva1 = () => Console.WriteLine("my void action"); // not allowed, why?
        MyClass meClass = new MyClass();
        meClass.MyVoidAction = () => Console.WriteLine("my void action");
        meClass.MyVoidAction();
    }
}

我查了一下这个答案:Accessibility between Action and Delegate

这清理了很多,但我不确定我是100%的。所以根据那个答案,委托void MyDeler()定义了一个类型,这让我感到困惑,因为我想象的是:

using System;

class MainClass
{
    class MyClass
    {
        public static class DelegateClass
        {
            public void DoDel() // isn't even legal?
            {
                Console.WriteLine("DoDel()");
            }
        }
    }
    static void Main()
    {
        //MyClass.DelegateClass d = new asdf // ??? something like this?
    }
}

帮助表示赞赏!

4 个答案:

答案 0 :(得分:0)

MyDeler类型声明,而不是变量声明。您无法将内容存储在其中或分配给它。

要创建用于存储MyDeler实例的字段,请将此行添加到MyClass

public MyDeler MyDelerField;

现在你可以分配给它了。

答案 1 :(得分:0)

  

为什么MyDeler是“静态的”,因为我可以通过类名访问MyDeler,但我无法明确说公共“静态”委托void MyDeler(),也不能通过MyClass的实例访问d,如在新的MyClass.d()?

MyDeler的声明在MyClass中声明类型。它类似于声明任何其他嵌套类型,如:

class MyClass
{
    public class MyNestedClass { }
}

它是类型 MyClass的成员,不是MyClass的任何实际实例,也不是MyClass类{{1}成员将是。

嵌套类型既不是“实例”也不是“静态”,因为它是类型系统的一部分,而不是类本身的一部分。

  

为什么我必须新建一个MyClass才能使用MyVoidAction?

因为static 是该类的成员,并且是实例成员。因此,您需要拥有该类的实例才能访问它。

  

委托void MyDeler()定义了一个类型,这让我感到困惑,因为我想象这样的事情

你在MyVoidAction的例子中的声明正在做一些完全不同的事情。 C#的一个不幸的方面是使用public static class DelegateClass来引用各种不同的东西。它不像Java那么糟糕,但它仍然可能令人困惑(正如你所发现的那样)。

在该声明中,使用单词static使使static成为包含类型DelegateClass的“静态成员”。相反,MyClass声明作为static声明的一部分,意味着整个班级仅包含class个成员。

因此,当您在没有static关键字的情况下声明DoDel()时,您试图在您承诺仅声明静态成员的类中声明实例成员,即该方法。如果将static添加到方法声明中,它将进行编译。

不这样做会使该示例中的static类与其他示例中的DelegateClass成员类似。它仍然是类型声明,在MyVoidAction类中声明嵌套类型,并且仍然遵循类型规则,而不是类成员。但我希望至少可以向你解释为什么令你困惑的例子就像它一样。

答案 2 :(得分:0)

让我们揭开神秘面纱:

当您声明MyDeler

public delegate void MyDeler();

您正在做的是定义一种执行方式"委托"。换句话说,你说有一个跟随这个签名的方法,我打算继续引用它。为了让编译器识别这些引用,将使用此类型。

接下来你需要实际拥有一个指向该方法的真实指针,因为这只是你的定义"。这就是为什么你需要一个类型变量" MyDeler"您可以为其分配要调用的实际方法:

MyClass.MyDeler d = () => Console.WriteLine("my deler");

这一行说"创建一个名为d的类型为MyClass.MyDeler的变量,该变量包含对此内联方法的引用"。从这里开始,当你调用d();时,指针实际上会执行内联方法。

对于行动:

public Action MyVoidAction;

您现在宣布该类的公开属性。因此,在使用此属性之前,您需要该类的实例。

这里的技巧是Action是委托的已知定义。 Microsoft有一个内置类型,您可以使用它而不是声明自己的void MyDeler();。它本质上是语法糖但记住,它仍然是一个类型,并且你已经创建了一个公共属性,你现在需要为它分配实际执行的方法,正如我们之前讨论的那样,你需要一个实例:

MyClass meClass = new MyClass(); //Instance creation
meClass.MyVoidAction = () => Console.WriteLine("my void action"); //Tell your delegate what to delegate to.
meClass.MyVoidAction(); //Run the inline method!

我希望有所帮助。

答案 3 :(得分:0)

Actiondelegate没有参数且返回void的方法正式相同。

如果您查看:https://msdn.microsoft.com/en-us/library/system.action(v=vs.110).aspx,您可以看到:

  

您可以使用此委托将方法作为参数传递   明确声明自定义委托。

我希望这个例子有所帮助:

public delegate void DelegateMyDeler(); //This is a custom delegate

public class MyClass
{
    public DelegateMyDeler MyDeler; //This use your custom delegate
    public Action MyVoidAction; // This use Action delegate
}

class MainClass
{
    static void Main()
    {
        // MyClass.MyDeler d = () => Console.WriteLine("my deler"); // Now this is not allowed too!
        // d();
        //  MyClass.MyVoidAction mva1 = () => Console.WriteLine("my void action"); // not allowed, why?
        MyClass meClass = new MyClass();

        meClass.MyDeler = () => Console.WriteLine("my deler");
        meClass.MyDeler();

        meClass.MyVoidAction = () => Console.WriteLine("my void action");
        meClass.MyVoidAction();

        //but you can do (you custom delegate is defined out of the class in this case
        //so you have not to add the class prefix):
        DelegateMyDeler d = () => Console.WriteLine("my deler 2");
        d();

        // or
        DelegateMyDeler d3 = () => Console.WriteLine("my deler 3");
        d3.Invoke();

        // and in a real case, for example:
        DelegateMyDeler undeterminedMethod;

        int x = 3;
        switch (x)
        {
            case 1:
                undeterminedMethod = deler1;
                break;
            case 2:
                undeterminedMethod = deler2;
                break;
            case 3:
                undeterminedMethod = deler3;
                break;
            default:
                undeterminedMethod = null;
                break;
        }

        undeterminedMethod?.Invoke(); //In case x is minor than 1 or major than 3, nothing happens

    }

    static void deler1() { Console.WriteLine("my deler 1"); }
    static void deler2() { Console.WriteLine("my deler 2"); }
    static void deler3() { Console.WriteLine("my deler 3"); }
}