C# 结构默认值

2024-06-07

我有一个方法,它接受一个包含许多具有基本数据类型的字段的结构。

我想传递大部分默认值,但需要进行一些调整,但我了解结构声明中的基本字段不能包含默认值声明,例如struct S{ int a = 42 }.

现在是这样的:

OptionsStruct options = OptionStructDefaults;
options.itemA = 2;
options.itemQ = 2; // ... itemB, itemR, itemAZ12, etc.

SetOptions(options);

然而,感觉很奇怪OptionsStructDefaults与信息分开的OptionsStruct宣言...

感觉好像有办法做这样的事情?

SetOptions( new OptionsStruct(){
    itemA = 2,
    itemQ = 2,
    // ...all other fields have default values.
}) 

Or:

SetOptions( new OptionsStruct(useDefaults:true){
    itemA = 2,
    itemQ = 2,
});

或者,是否有理由单独指定结构默认值是最终的处理方式?


Update:在 C# 10+ (.NET 6+) 中,此限制被解除。你现在can结构上有默认构造函数,并且您还can就地初始化字段和属性。像编写一个类一样编写您的结构,它将起作用:

public struct OptionsStruct
{
    public int ItemA { get; set; } = 2;
    public int ItemQ { get; set; } = 2;
}
    SetOptions(new OptionsStruct()
    {
        ItemA = 3,
        // ...all other fields have default values.
    });

但是,有两个问题需要注意:

  • 如果结构上没有构造函数或无参数构造函数,则字段和属性初始化将正常工作。但是,如果您有带参数的构造函数但没有无参数构造函数,它们将不起作用。如果你有一个带参数的构造函数,也要写一个无参数的构造函数(即使它是空的),所以当你写new MyStruct(),字段和属性将按照您的预期进行初始化。 (此行为是为了与以前的行为(当所有参数都是可选时不调用构造函数)保持向后兼容性。有关示例,请参阅此答案的最后一个代码块。)

    public struct NoConstructor
    {
        public int Item { get; set; } = 42;
    }
    
    public struct ParameterlessConstructor
    {
        public int Item { get; set; } = 42;
    
        public ParameterlessConstructor() { }
    }
    
    public struct WithParameterConstructor
    {
        public int Item { get; set; } = 42;
    
        public WithParameterConstructor(int item)
        {
            Item = item;
        }
    }
    
    public struct BothConstructors
    {
        public int Item { get; set; } = 42;
    
        public BothConstructors() { }
    
        public BothConstructors(int item)
        {
            Item = item;
        }
    }
    
        Console.WriteLine(new NoConstructor().Item); // 42
        Console.WriteLine(new ParameterlessConstructor().Item); // 42
        Console.WriteLine(new WithParameterConstructor().Item); // 0
        Console.WriteLine(new BothConstructors().Item); // 42
    
  • 无参数构造函数不保证始终被调用,因此不要依赖始终初始化的字段和属性。如果您创建一个结构体数组,例如new MyStruct[5],或者如果你使用default or default(MyStruct),不会调用构造函数,并且字段和属性将初始化为默认值(0 or false or null),就像 C# 10 之前的情况一样。

    public struct MyStruct
    {
        public int FortyTwo { get; } = 42;
    
        public int GetFortyThree()
        {
            return FortyTwo + 1;
        }
    }
    
    public class SomeClass
    {
        MyStruct myStruct; // not initialized, same as default(MyStruct)
    
        public int GetFortyThree()
        {
            return myStruct.GetFortyThree();
        }
    }
    
        Console.WriteLine(new MyStruct().GetFortyThree()); // 43
        Console.WriteLine(default(MyStruct).GetFortyThree()); // 1
        var array = new MyStruct[5];
        Console.WriteLine(array[0].GetFortyThree()); // 1
        Console.WriteLine(new SomeClass().GetFortyThree()); // 1
    

以下是有关 C# 10 / .NET 6 新功能的文档链接:无参数构造函数和字段初始值设定项 https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#parameterless-constructors-and-field-initializers

对于 C# 9 及更低版本,请继续阅读...


的限制struct是你不能拥有default构造函数。因此,您不能为字段和属性设置默认值(因为它被编译到默认构造函数中)。

But you can有一个非默认构造函数,即带有参数的构造函数。

所以你可以有一个struct像这样:

public struct OptionsStruct
{
    public int ItemA { get; set; }
    public int ItemQ { get; set; }

    public OptionsStruct(bool useDefaults)
    {
        if (useDefaults)
        {
            ItemA = 2;
            ItemQ = 2;
        }
        else
        {
            ItemA = 0;
            ItemQ = 0;
        }
    }
}

并按照您所写的那样使用它:

    SetOptions(new OptionsStruct(useDefaults:true)
    {
        ItemA = 3,
        // ...all other fields have default values.
    });

另一种方法是有一个static设置默认值的方法:

public struct OptionsStruct
{
    public int ItemA { get; set; }
    public int ItemQ { get; set; }

    public static OptionsStruct GetDefault()
    {
        return new OptionsStruct()
        {
            ItemA = 2;
            ItemQ = 2;
        };
    }
}

并像这样使用它:

    var options = OptionsStruct.GetDefault();
    options.ItemA = 3;
    SetOptions(options);

如果你的属性数量不是太多,你还可以使用带有可选参数的构造函数:

public struct OptionsStruct
{
    public int ItemA { get; set; }
    public int ItemQ { get; set; }

    public OptionsStruct(int itemA = 2, int itemQ = 2)
    {
        ItemA = itemA;
        ItemQ = itemQ;
    }
}

但只有当你给它至少一个参数时才会调用它:

    var options1 = new OptionsStruct(); // The "default" constructor is called, so everythng will be 0.
    Console.WriteLine(options1.ItemA); // 0
    Console.WriteLine(options1.ItemQ); // 0

    var options2 = new OptionsStruct(3); // Everything works as expected.
    Console.WriteLine(options1.ItemA); // 3
    Console.WriteLine(options1.ItemQ); // 2
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 结构默认值 的相关文章

随机推荐

  • Three.js:为相机添加灯光

    我想移动和旋转相机 但将点光源保持在相对于相机的相同位置 我读过很多帖子 说您可以将灯光对象添加到相机而不是场景中 就像这样 pointLight new THREE PointLight 0xffffff pointLight posit
  • 如何在 Scala 用户定义注释中使用命名参数?

    在下面的代码中 我能够获得第一个注释对象 Publishable 但不能获得第二个 第二个使用命名参数 它转换为 x 2 x 3 x 1 作为 AST 中的参数 我该如何正确地做到这一点 class Publishable val path
  • iOS 框架问题:类在两者中均实现

    我正在开发一个使用第三方框架类的iOS框架项目 所以我在下面添加了第三方框架链接的框架和库部分 当我在 iOS 应用程序项目中添加自定义框架时 每个类都会收到此警告 objc 3139 类 class name 在两者中均实现 privat
  • 是否可以创建一个在函数的泛型类型上具有特征边界的类型别名?

    这段代码 pub type Foo
  • 如何检查 Flutter 应用程序是否正在调试中运行?

    我正在寻找一种在应用程序处于调试模式时在 Flutter 中执行代码的方法 在 Flutter 中这可能吗 我似乎无法在文档中的任何地方找到它 像这样的东西 If app inDebugMode print Print only in de
  • 在批处理管道中,如何为来自批处理源的数据分配时间戳,例如 Beam 管道中的 csv 文件

    我正在批处理管道中从有界源 csv 文件 读取数据 并希望根据存储为 csv 文件中列的数据为元素分配时间戳 如何在 Apache Beam 管道中执行此操作 如果您的批量数据源包含每个元素基于事件的时间戳 例如您有一个包含元组的点击事件
  • css 变换,chrome 中的锯齿状边缘

    我一直在使用 CSS3 转换来旋转网站中带有边框的图像和文本框 问题是 Chrome 中的边框看起来呈锯齿状 就像没有抗锯齿的 低分辨率 游戏一样 在 IE Opera 和 FF 中看起来好多了 因为使用了 AA 仍然清晰可见 但也没有那么
  • 如何在matplotlib中控制鼠标悬停文本

    当您将鼠标悬停在使用 imshow 显示的图像上时 您可以将鼠标悬停在该图像上以检查其 RGB 值 matplotlib 窗口的右下角 与工具栏共享空间 显示了所指向像素的图像坐标和 RGB 值 x 274 99 y 235 584 241
  • 如何在 C# 中以编程方式将行添加到 DataGrid?

    正如标题所述 我正在尝试使用 C 以编程方式将行添加到 DataGrid 但我似乎无法使其工作 这是我到目前为止所拥有的 I have a DataGrid declared as dg in the XAML foreach string
  • npm 错误! asyncWrite 不是一个函数

    npm 安装 g firebase tools npm 错误 asyncWrite 不是一个函数 npm 错误 pna nextTick 不是函数 npm 错误 此运行的完整日志可以在以下位置找到 npm 错误 home developer
  • Windows Phone 7 - ScrollViewer 值已更改

    我一直在寻找解决方案 但无法找到正确的解决方案 我的网格宽度为 960 并且有ScrollViewer在里面 现在我想知道滚动时滚动的值 水平偏移 我找到的所有解决方案都是针对 wpf silverlight 的 它对我不起作用 Edit
  • 如何在 Linux 上重新实现(或包装)系统调用函数?

    假设我想完全接管 open 系统调用 也许要包装实际的系统调用并执行一些日志记录 一种方法是使用 LD PRELOAD http scaryreasoner wordpress com 2007 11 17 using ld preload
  • Android 中 Admob 的 XML 或 Java 关键字

    我似乎找不到任何有关通过 XML 或 Java 设置 adMob 广告关键字的可靠文档 我已经尝试过中看到的方法this https stackoverflow com questions 5066129 android admob api
  • 如果是数字,Chrome 会重新排序对象键,这是正常/预期的吗

    我注意到某些评估电子商务网站的某些鞋码并将其输出到屏幕上的代码会打乱 Chrome 中的顺序 给出的 JSON 可以是 7 9149 9139 10455 17208 7 5 9140 9150 10456 17209 8 2684 914
  • Phantomjs page.content 未检索页面内容

    我使用 Phantomjs 来抓取使用 JavaScript 和 Ajax 加载动态内容的网站 我有以下代码 var page require webpage create page onError function msg trace v
  • telethon 库:如何通过电话号码添加用户

    我正在研究 Telegram 的 Telethon 库 它可以使用 Telegram API 充当 Telegram 客户端 重要提示 这是电报客户端 API https core telegram org telegram api 而不是
  • 在 C# 中解析 JS Date.toIsoString

    我需要将 JS 日期存储为 ISO 8601 日期 我目前正在从格式为 2019 06 22T00 00 00 000Z 的表单中获取日期 正如 JS 的 toIsoString 方法所期望的那样 当这个日期传递到我的 API 控制器时 我
  • TypeError:“NoneType”对象不可下标[重复]

    这个问题在这里已经有答案了 错误 names curfetchone 0 TypeError NoneType object is not subscriptable 我尝试检查缩进 但仍然有错误 我读到 如果数据库中没有文件名记录 变量名
  • 设置 D3 力定向图

    致尊敬的读者 我对 javascript 相当陌生 我也遇到过这个问题 我正在尝试实现这个力导向图的修改版本 http mbostock github com d3 ex force html http mbostock github co
  • C# 结构默认值

    我有一个方法 它接受一个包含许多具有基本数据类型的字段的结构 我想传递大部分默认值 但需要进行一些调整 但我了解结构声明中的基本字段不能包含默认值声明 例如struct S int a 42 现在是这样的 OptionsStruct opt