为什么在没有首先将其分配给任何东西的情况下调用操作是合法的

本文关键字:情况下 调用 操作 任何东 分配 为什么 | 更新日期: 2023-09-27 18:34:24

我对 C# 中的操作的理解是,它们只是委托的特定版本,即没有参数和返回类型的委托。

如果我创建一个这样的类...

class TrainSignal
{
    public delegate void TrainsAComing();
    public void HerComesATrain()
    {
        TrainsAComing();
    }
}

。它不会编译,因为我还没有创建委托的实例。但是,如果我将委托定义替换为如下所示的操作定义,它将编译:

class TrainSignal
{
    public Action TrainsAComing;
    public void HerComesATrain()
    {
        TrainsAComing();
    }
}

我想也许一个动作是静态的或类似的东西(从而允许我们用它的名字来调用它而不实例化它),但事实似乎并非如此。

谁能解释为什么第二个代码块是合法的?

为什么在没有首先将其分配给任何东西的情况下调用操作是合法的

此行

public delegate void TrainsAComing();

定义一个名为 TrainsAComing 的公共委托类型,嵌套在类中。这将允许用户创建类型为 TrainSignal.TrainsAComing 的委托,但TrainSignal将没有成员来存储此类委托的实例。

换句话说,委托的声明定义委托类型的成员。您需要另一个声明:

class TrainSignal
{
    public delegate void TrainsAComing(); // The delegate type
    public TrainsAComing OnTrainsAComing; // The member of delegate type
    public void HerComesATrain()
    {
        OnTrainsAComing();
    }
}

另一方面,Action已经是一种类型,类似于示例中delegate TrainsAComing。因此,定义

public Action TrainsAComing;

使TrainsAComing成为能够存储委托的TrainSignal的成员。

Action字段与其他字段一样。它是 ref 类型,因此null初始化该字段。您将收到NullReferenceException。这是完全安全的,但没有用。

也许你的意思是实际引用一个函数?

Action TrainsAComing = () => Console.WriteLine("...");

或者,混淆来自这样一个事实,即第一个代码段声明委托类型,第二个代码段声明委托类型的字段。