C# - 无法在方法内声明委托

15

我真的很茫然。

我想知道为什么我不能在方法内部声明代理类型,而是必须在类级别上这样做。

namespace delegate_learning
{
    class Program
    {
        // Works fine
        public delegate void anon_delgate(int i);

        static void Main(string[] args)
        {
            HaveFun();
            Console.Read();
        }

        public static void HaveFun()
        {
            // Throws an error :/
            //delegate void anon_delgate(int i);

            anon_delgate ad = delegate(int i) { Console.WriteLine(i.ToString());};
        }


    }
}

编辑:我正在研究Lambda表达式,并且为了自己的个人知识而回溯到Lambda之前的情况。


7
在方法中,您可以声明“任何”类型吗? - John Saunders
我认为Nawaz的回答很好,因为它强调了不同的作用域级别。如果将委托限定在方法内部,而不与其他方法通信,会有什么好处? - Steven
@Steven - 我脑海中首先想到的一个好处是,你可以将其限定在一个方法内,并直接为其分配一个匿名方法,在你声明委托的方法内使用。 - contactmatt
@contactmatt - 也许我错过了一些显而易见的东西,但我仍然看不到其中的好处。如果委托和方法都仅驻留在拥有方法的范围内,那么通过委托访问匿名方法相比直接访问匿名方法有什么优势呢? - Steven
6个回答

19
// Throws an error :/
delegate void anon_delgate(int i);

它报错了,因为它是一个类型定义,而不是一个变量声明。任何类型定义都不允许在方法内部,只允许在类作用域或命名空间作用域中使用。

namespace A
{
   delegate void X(int i); //allowed
   public class B
   {
         delegate void Y(int i); //also allowed
   }
}

顺便问一下,为什么不写成这样:

anon_delgate ad = i => Console.WriteLine(i.ToString());

它被称为lambda表达式。


1
+0: 我认为这有点在回避问题。Contactmatt正在问为什么“任何类型定义都不允许在方法内部。它只允许在类范围或命名空间范围内。” - Brian

12

在方法内部无法声明任何类型。那么让我们考虑“为什么我不能在C#方法中声明类型?”的问题。

对于这种形式的问题,答案总是相同的。要在C#中做某事,必须完成以下所有步骤:

  • 有人必须想到这个功能
  • 有人必须设计这个功能
  • 有人必须编写该功能的规范
  • 有人必须实现该规范
  • 有人必须测试该实现
  • 必须记录该功能(并将文档翻译成十几种不同的语言)
  • 以某种方式,实现代码必须进入可用于向客户交付的“载体”中。

到目前为止,在该列表上只发生了第一件事情。其他事情从未发生过,因此您不能在C#中使用该功能。

你似乎暗示了一个功能的默认状态是“已实施”,我们必须找到一些理由使其未实施。我向您保证,情况并非如此;所有可能功能的默认状态都是“未实施”,我们必须有理由花费时间、金钱和精力来实现一个功能。到目前为止,没有人提出过本地类型声明是有价值的充分理由;如果您想尝试提出充分理由,我很愿意听取。


1
对于不能在方法内声明任何类型的说法,匿名类型不是这样声明的吗?我知道它们没有被限定在方法内,但那是你可以定义它们的唯一上下文。或者在词汇表中,“声明”一词对于匿名类型是否有不同的含义? - LBushkin
1
@LBushkin: 这是一个很好的观点。一方面,当然,在方法内部说匿名类型被“定义”或“声明”是有道理的。但在另一方面,匿名类型根本没有被声明。我会说,“声明”某个东西是将从名称到某个实体的映射引入到声明空间中。匿名类型没有名称,因此永远不会被“声明”。 - Eric Lippert

5
在方法内声明委托就像在方法内声明类一样,因为编译器将委托声明重写为类声明。这就是为什么你不能这样做,而委托类型分配是完全有效的。

或者说:因为委托是一种类型,就像类一样。编译器如何处理它并不是问题所在。 - H H

2
能够随时创建任意委托是有用的,但给它们不同但匿名类型似乎没那么有用。无论是否使用Lambda表达式,您都可以将anon_delegate ad替换为Action<int>。由于方法外部没有人能看到anon_delegate,所以它的存在并没有增加非凡的价值。您想要在本地定义委托类型,但您可以将关于委托目的的任何信息编码到变量的名称中,而不是变量的类型中。已经定义了数十个ActionFunc委托,因此很少会找不到适合您需求的委托。

简而言之,我认为这个功能增加了一些重大的成本,但我认为它并没有足够的好处来抵消这些成本,更别说提供另一个可能会让开发人员困惑的功能所带来的额外混乱了。

这个功能并没有为语言增加任何表现力,它的不存在很容易被解决,并且我认为它会浪费更多开发者的时间(使得C#更难学/用)而不是节省时间。
(在旧版的C#中可能有较少的这种功能,但当问到为什么一个功能在旧版的C#中没有时,如果答案是“哇,这真的很有用,我们把它添加到了下一个版本中”,那就显得相当无聊了。)

1

你为什么不直接使用Lambda表达式呢?

Action<int> ad = i => Console.WriteLine(i.ToString());

你不能将lambda表达式分配给隐式类型变量。(在这种情况下,var会是什么?Action<int>Action<Foo>?) - dlev
是的,我总是忘记C#有限制...已修复。 - Ramon Snir

0

因为委托是一个公共方法签名,旨在让类的用户在其端遵守。这是一种说法:“如果您公开此方法并使用这些参数,我可以在必要时调用它”的方式。

方法内部不会在类外部公开 - 只有签名 - 因此在私有类中声明方法签名是没有意义的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接