【问题标题】:Difference between Action and delegate instantiation and accessibilityAction 和委托实例化和可访问性之间的区别
【发布时间】:2017-07-19 21:08:22
【问题描述】:

为什么 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?
    }
}

帮助表示赞赏!

【问题讨论】:

    标签: c# delegates action


    【解决方案1】:

    让我们揭开它的神秘面纱:

    当你声明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!
    

    希望对你有帮助。

    【讨论】:

      【解决方案2】:

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

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

      public MyDeler MyDelerField;
      

      现在你可以分配给它了。

      【讨论】:

        【解决方案3】:

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

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

        class MyClass
        {
            public class MyNestedClass { }
        }
        

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

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

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

        因为MyVoidAction类的成员,并且是instance的成员。所以你需要有一个类的instance才能访问它。

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

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

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

        因此,当您声明 DoDel() 而不使用 static 关键字时,您是在尝试在您承诺仅声明静态成员的类中声明实例成员,即该方法。如果在方法声明中添加static,它将编译。

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

        【讨论】:

        • 啊,这真是让我的大脑发痒。我以前不熟悉嵌套类。
        【解决方案4】:

        Action 和一个没有参数并返回void 的方法的delegate 在形式上是相同的。

        如果你看一下: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"); }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-10
          • 2011-09-17
          • 2010-11-21
          • 1970-01-01
          • 1970-01-01
          • 2010-12-13
          相关资源
          最近更新 更多