簡體   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