返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C# Record构造函数的行为更改详解
  • 509
分享到

C# Record构造函数的行为更改详解

2024-04-02 19:04:59 509人浏览 安东尼
摘要

如何更改 C# Record 构造函数的行为 Record[1] 是 C# 9 中的一个新功能。Record是从Structs[2]借用的特殊类, 因为它们具有 基于值的相等性,您可

如何更改 C# Record 构造函数的行为

Record[1] 是 C# 9 中的一个新功能。Record是从Structs[2]借用的特殊类, 因为它们具有 基于值的相等性,您可以将它们视为两类类型之间的混合体。默认情况下,它们或多或少是不可变的,并且具有语法糖,使声明更容易和更简洁。但是,语法糖可能会掩盖更多标准任务,例如更改默认构造函数的行为。在某些情况下,您可能需要这样做以进行验证。本文将向您展示如何实现这一目标。

以这个简单的示例类为例:


public class StringValidator
{
    public string InputString { get; }


    public StringValidator(string inputString)
    {
        if (string.IsNullOrEmpty(inputString)) throw new ArgumentNullException(nameof(inputString));


        InputString = inputString;
    }
}

很明显,如果消费者试图在没有有效字符串的情况下创建此类的实例,他们将收到异常。创建Record的标准语法如下所示:


    public record StringValidator(string InputString);

它既友好又简洁,但并不清楚您将如何验证字符串。此定义告诉编译器将有一个名为 的属性InputString,并且构造函数会将值从参数传递给该属性。我们需要删除语法糖来验证字符串。幸运的是,这很容易。我们不需要使用新语法来定义我们的Record。我们可以定义类似于类的Record,但将关键字类更改为Record。


public record StringValidator
{
    public string InputString { get;  }


    public StringValidator(string inputString)
    {
        if (string.IsNullOrEmpty(inputString)) throw new ArgumentNullException(nameof(inputString));


        InputString = inputString;
    }
}

不幸的是,这意味着我们不能使用 非破坏性突变[3]。该with关键字给我们创造了一些属性来更改Record的新版本的功能。这意味着我们不会修改Record的原始实例,但我们会得到它的副本。这是 Fluent api 和函数式编程的常用方法。这使我们能够保持不变性。

为了允许非破坏性突变,我们需要添加init属性访问器。这与构造函数的工作方式类似,但仅在对象初始化期间调用。这是实现init访问器的更完整的解决方案。这允许您共享构造函数逻辑和初始化逻辑。


using System;


namespace ConsoleApp25
{
    class Program
    {
        static void Main(string[] args)
        {
            //This throws an exception from the constructor
            //var stringValidator = new StringValidator(null);


            var stringValidator1 = new StringValidator("First");
            var stringValidator2 = stringValidator1 with { InputString = "Second" };
            Console.WriteLine(stringValidator2.InputString);


            //This throws an exception from the init accessor
            //var stringValidator3 = stringValidator1 with { InputString = null };


            //Output: Second
        }
    }


    public record StringValidator
    {
        private string inputString;


        public string InputString
        {
            get => inputString;
            init
            {
                //This init accessor works like the set accessor
                ValidateInputString(value);
                inputString = value;
            }
        }


        public StringValidator(string inputString)
        {
            ValidateInputString(inputString);
            InputString = inputString;
        }


        public static void ValidateInputString(string inputString)
        {
            if (string.IsNullOrEmpty(inputString)) throw new ArgumentNullException(nameof(inputString));
        }
    }
}

Record构造函数应该有逻辑吗?

这是一个有争议的辩论,超出了本文的范围。很多人会争辩说你不应该把逻辑放在构造函数中。Record的设计鼓励您不要在构造函数或 init 访问器中放置逻辑。一般来说,Record应该及时代表数据的快照状态。您不需要应用逻辑,因为假设您知道此时数据的状态。但是,就像其他所有编程结构一样,无法知道Record可能会产生哪些用例。这是库 Urls 中的[4]一个示例[5][6]它将 URL 视为不可变Record:


using System.net;


namespace Urls
{
    public record QueryParameter
    {
        private string? fieldValue;


        public string FieldName { get; init; }
        public string? Value
        {
            get => fieldValue; init
            {
                fieldValue = WEBUtility.UrlDecode(value);
            }
        }


        public QueryParameter(string fieldName, string? value)
        {
            FieldName = fieldName;
            fieldValue = WebUtility.UrlDecode(value);
        }


        public override string ToString()
            => $"{FieldName}{(Value != null ? "=" : "")}{WebUtility.UrlEncode(Value)}";
    }
}

我们确保在存储查询值时对其进行解码,然后在将其用作 Url 的一部分时对其进行编码。

你可能会问:为什么不把一切都Record下来?似乎会有与此相关的陷阱,但我们正在冒险进入新领域,我们尚未为 C# 上下文中的Record制定最佳实践。

总结

开发人员需要几年时间才能接受Record并制定使用它们的基本规则。您目前有一张白纸,您可以自由尝试,直到“专家”开始告诉您其他情况。我的建议是只使用Record来表示固定数据和最小逻辑。尽可能使用语法糖。但是,在某些情况下,构造函数中的最小验证可能是可行的。运用你的判断力,与你的团队讨论,权衡利弊。

到此这篇关于C# Record构造函数行为更改的文章就介绍到这了,更多相关C# Record构造函数内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

References

[1] Record: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/records

[2] Structs: Https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct

[3] 非破坏性突变: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/records#non-destructive-mutation

[4] Urls 中的: https://GitHub.com/MelbourneDeveloper/Urls

[5] 示例: https://github.com/MelbourneDeveloper/Urls/blob/5f55a9437cfac1223711d616bfdbeb72b230d263/src/Uris/QueryParameter.cs#L5

[6] , : https://github.com/MelbourneDeveloper/Urls

--结束END--

本文标题: C# Record构造函数的行为更改详解

本文链接: https://lsjlt.com/news/133884.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C# Record构造函数的行为更改详解
    如何更改 C# Record 构造函数的行为 Record[1] 是 C# 9 中的一个新功能。Record是从Structs[2]借用的特殊类, 因为它们具有 基于值的相等性,您可...
    99+
    2024-04-02
  • C#构造函数详解
    一、简介 构造函数,基本用法是在类对象声明的时候完成初始化工作。 二、实例构造函数 1、构造函数的名字与类名相同。 2、使用 new 表达式创建类的对象或者结构(例如int)时,会调...
    99+
    2024-04-02
  • 详解C++构造函数
    目录1.作用2.代码举例2.1 示例1:2.2 示例2:3. 使用3.1 使用构造函数初始化3.2 有参数的构造函数3.3 默认的构造函数4. 成员初始化列表例1:正常初始化例2:成...
    99+
    2024-04-02
  • C++构造函数详解
    文章转自公众号:Coder梁(ID:Coder_LT) 上一篇文章我们介绍了定义了类,在使用之前,往往还需要对类进行初始化。这篇介绍的就是对类进行初始化的方法。 像是结构体,我们可以...
    99+
    2024-04-02
  • C++:构造函数,析构函数详解
    目录前言一、面向对象二、构造函数1.基本概念2.构造函数重载1.构造函数分类2.有参构造函数:3.有参构造函数3个调用规则:4.拷贝构造函数5.析构函数总结前言 上期了解C++类中有...
    99+
    2024-04-02
  • C++中的构造函数详解
    目录普通变量的初始化构造函数一定会生成默认构造函数吗?防止隐式类型转换赋值与初始化的区别对象的计数成员初始化的顺序类的引用成员构造函数使用注意事项参考总结普通变量的初始化 当我们在定...
    99+
    2024-04-02
  • C++中构造函数详解
    构造函数按参数为为:有参构造函数和无参构造函数 按类型分为:普通构造函数和拷贝构造函数 构造函数的三种调用方法:括号法,显示法,隐式转换法; //括号法 Person p1; ...
    99+
    2024-04-02
  • 怎么更好的进行C++构造函数
    今天就跟大家聊聊有关怎么更好的进行C++构造函数,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。构造函数是开发过程中的一种特殊的方法,其主要用来在创建对象时的初始化对象,也就是对象成员...
    99+
    2023-06-17
  • c++特殊构造函数详解
    目录前言拷贝构造函数一、什么是拷贝构造函数二、调用时机注意浅拷贝和深拷贝总结前言 众所周知,构造函数的作用是类在创建对象时的初始化,而拷贝构造函数则是构造函数里的一种特殊构造。 拷贝...
    99+
    2024-04-02
  • C++中的复制构造函数详解
    目录复制构造函数复制构造函数的三种调用复制构造函数的禁用深拷贝与浅拷贝一定会生成默认复制构造函数吗?参考 总结普通变量的复制 有时我们会在定义一个变量的同时使用另一个变量来初始化它。...
    99+
    2024-04-02
  • C++中的拷贝构造函数详解
    目录C++拷贝构造函数(复制构造函数)详解1) 为什么必须是当前类的引用呢?2) 为什么是 const 引用呢?默认拷贝构造函数总结C++拷贝构造函数(复制构造函数)详解 拷贝和复制...
    99+
    2024-04-02
  • C++超详细讲解构造函数
    目录类的6个默认成员函数构造函数特性编译器生成的默认构造函数成员变量的命名风格类的6个默认成员函数 如果我们写了一个类,这个类我们只写了成员变量没有定义成员函数,那么这个类中就没有函...
    99+
    2024-04-02
  • C++构造函数的初始化列表详解
    目录1.问题2.解决方法(初始化列表)3.顺序问题总结 1.问题 class A { private: int m_a; public: A(int a) { cout ...
    99+
    2024-04-02
  • C++中拷贝构造函数的总结详解
    1.什么是拷贝构造函数: 拷贝构造函数嘛,当然就是拷贝和构造了。(其实很多名字,只要静下心来想一想,就真的是顾名思义呀)拷贝又称复制,因此拷贝构造函数又称复制构造函数。百度百科上是这...
    99+
    2022-11-15
    拷贝构造函数 C++
  • C++超详细讲解拷贝构造函数
    目录构造函数特征编译器生成的拷贝构造拷贝构造的初始化列表显式定义拷贝构造的误区结论构造函数 只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对...
    99+
    2024-04-02
  • C++类与对象及构造函数析构函数基础详解
    目录C++类与对象类的定义对象的创建构造函数和析构函数访问修饰符继承多态成员变量与成员方法总结C++类与对象 C++是一门面向对象的编程语言。在C++中,我们可以利用类来创建对象,...
    99+
    2023-05-16
    C++类对象函数 c++ 构造析构函数
  • 正确理解C++的构造函数和析构函数
    目录一、构造函数二、C++类的内存模型2.1、只定义成员函数2.2、往空类中添加静态成员变量2.3、再加入非静态成员变量三、this指针四、析构函数一、构造函数 首先,由于类只是一个...
    99+
    2024-04-02
  • c++详细讲解构造函数的拷贝流程
    #include <iostream> #include <string> using namespace std; void func(string str...
    99+
    2024-04-02
  • C++实现拷贝构造函数的方法详解
    目录引入一.什么是拷贝构造函数二.什么情况下使用拷贝构造函数三.使用拷贝构造函数需要注意什么四.深拷贝浅拷贝4.1 浅拷贝4.2 深拷贝引入 对于普通类型的对象来说,他们之间的复制很...
    99+
    2024-04-02
  • C++中构造函数与析构函数的详解及其作用介绍
    目录构造函数默认构造函数有参构造函数析构函数析构函数例子析构函数执行时机局部对象全局对象构造函数 构造函数 (constructor) 是一种特殊的成员函数. 它会在每次创建类的新对...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作