繁体   English   中英

您可以在 c# 中的只读结构上设置默认参数吗?

[英]Can you have default parameters on a readonly struct in c#?

似乎默认参数不适用于 c# 中的只读结构。 我是不是误会了什么?

   public readonly struct ReadonlyStruct
   {
      public ReadonlyStruct(int p1 = 1, byte p2 = 2, bool p3 = true)
      {
         P1 = p1;
         P2 = p2;
         P3 = p3;
      }

      public int P1 { get; }
      public byte P2 { get; }
      public bool P3 { get; }
   }

使用var test = new ReadonlyStruct(); 似乎不遵守默认值。 我究竟做错了什么?

与直觉相反,您不能在struct上拥有所有默认参数或显式无参数构造函数,这不仅限于readonly struct

与 class 不同, struct值类型,不需要有构造函数,因此在您的情况下,您根本不提供任何参数,因此构造函数永远不会被调用。

如文档中所述

结构类型设计的限制

设计结构类型时,您具有与 class 类型相同的功能,但以下情况除外:

您不能声明无参数构造函数。 每个结构类型都已经提供了一个隐式的无参数构造函数,该构造函数产生该类型的默认值。

当您不提供参数时,生成的 IL 将调用

OpCodes.Initobj 字段

将指定地址的值类型的每个字段初始化为 null 引用或相应原始类型的 0。

此外

与 Newobj 不同,initobj 不调用构造函数方法。 Initobj 用于初始化值类型,而 newobj 用于分配和初始化对象。

相反,在以下情况下它会。 默认值将以您期望的方式初始化。

var asd = new ReadonlyStruct(2);

以下生成的 IL 将是

newobj instance void ReadonlyStruct::.ctor(int32, uint8, bool)

OpCodes.Newobj 字段

newobj 指令分配与 ctor 关联的 class 的新实例,并将新实例中的所有字段初始化为 0(适当类型)或 null 引用。 然后,它使用给定的 arguments 以及新创建的实例调用构造函数 ctor。 调用构造函数后,将现在初始化的 object 引用(类型 O)压入堆栈。

简而言之,您可能需要重新考虑您的问题或使用 static 创建方法。

C# 中的可选参数始终以这种方式工作。 对于任何给定的调用,如果有两个适用的重载,一个要求编译器使用默认值作为参数的参数,而另一个没有,则不需要它的那个“获胜”。 这是一个简单的例子:

using System;

class Test
{
    static void Main()
    {
        // Prints "Parameterless"
        Foo();
    }

    static void Foo() =>
        Console.WriteLine("Parameterless");

    static void Foo(int x = 0) =>
        Console.WriteLine("Parameterized");
}

接下来,请记住每个结构都隐式地具有一个无参数构造函数。 来自 C# 5 ECMA 标准,第 16.4.9 节:

与 class 不同,不允许结构声明无参数实例构造函数。 相反,每个结构都隐含了一个无参数的实例构造函数,它总是返回将所有值类型字段设置为其默认值并将所有引用类型字段设置为null的值。

把这两个事实放在一起,你看到的行为就很合理了。 当您不指定任何参数时,无参数构造函数优先于参数化构造函数。 您可以使用 class 看到完全相同的内容,其中无参数构造函数是显式的:

using System;

class Test
{
    static void Main()
    {
        // Prints "Parameterless"
        Foo f = new Foo();
    }
}

class Foo
{
    public Foo()
    {
        Console.WriteLine("Parameterless");
    }

    public Foo(int x = 0, int y = 0)
    {
        Console.WriteLine("Parameterized");
    }
}

所以你看到的是 C# 语言完全一致。 这可能不是您想要的行为,但我相信这是非常有意义的行为。

请注意,如果您指定任何arguments,例如new Foo(x: 0) ,则将选择参数化重载,并且默认值将用于任何没有相应参数的参数。

正如您在其他地方所说,解决此问题的方法是声明一个带有可选参数的 static 方法,该方法没有无参数重载。 这样,无论提供了 arguments,都会调用相同的方法 - 然后可以调用构造函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM