动作和委托实例化和可访问性之间的区别

Difference between Action and delegate instantiation and accessibility

为什么 MyDeler "static",因为我可以通过 class 名称访问 MyDeler,但我不能明确地说 public "static" delegate void MyDeler( ),也不能通过 MyClass 的实例访问 d,如 new 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?
    }
}

感谢帮助!

MyDelertype 声明,不是变量声明。你不能在其中存储东西或分配给它。

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

public MyDeler MyDelerField;

现在可以给它赋值了。

Why is MyDeler "static", as in I can access MyDeler through the class name, but I can't explicity say public "static" delegate void MyDeler(), nor can I access d through an instance of MyClass, as in new MyClass.d()?

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

class MyClass
{
    public class MyNestedClass { }
}

它是 类型 MyClass 的成员,而不是 MyClass 的任何实际实例,甚至 class MyClass 作为 static 成员。

嵌套类型既不是 "instance" 也不是 "static",因为它是 类型系统 的一部分,而不是 class 本身的一部分.

why is it that I have to new up a MyClass to use MyVoidAction?

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

the delegate void MyDeler() defines a type, which confuses me because I imagine something like this

您在 public static class DelegateClass 示例中的声明正在做完全不同的事情。 C# 的一个不幸方面是使用 static 来指代各种不同的事物。它不像 Java 中那么糟糕,但它仍然令人困惑(正如您所发现的那样)。

在该声明中,static 一词的使用 而不是 使 DelegateClass 成为包含类型 [=12] 的 "static member" =].相反,单词 static 作为 class 声明的一部分意味着 整个 class 将仅包含 static 个成员。

因此,当您在不使用 static 关键字的情况下声明 DoDel() 时,您试图在您承诺的 class 中声明一个实例成员,即该方法只声明静态成员。如果将 static 添加到方法声明中,它将编译。

并不是说这样做会使该示例中的 DelegateClass class 类似于另一个示例中的 MyVoidAction 成员。它仍然是一个 type 声明,在 MyClass class 中声明一个嵌套类型,并且仍然遵循类型规则,而不是 class 成员。但我希望至少能向您解释为什么让您感到困惑的示例会以它的方式工作。

让我们揭开这个神秘面纱:

当你声明 MyDeler:

public delegate void MyDeler();

您正在做的是定义一种将要执行的方法类型 "delegated"。换句话说,你是说这个签名后面有一个方法,我打算保留对它的引用。为了让编译器识别这些引用,将使用这种类型。

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

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

这一行表示 "create a variable named d of type MyClass.MyDeler that holds a reference to this inline method"。从这里开始,当您调用 d(); 时,指针将实际执行内联方法。

对于操作:

public Action MyVoidAction;

您现在正在声明 class 的 public 属性。因此,在使用此 属性.

之前,您需要一个 class 的实例

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

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!

希望对您有所帮助。

Action 和没有参数的方法的 delegate 和 returns void 在形式上是同一件事。

如果你看一下:https://msdn.microsoft.com/en-us/library/system.action(v=vs.110).aspx 你会看到:

You can use this delegate to pass a method as a parameter without explicitly declaring a custom delegate.

希望这个例子对您有所帮助:

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"); }
}