• 浅析 record 使用场景


    浅析 record 使用场景

    Intro

    之前我们有介绍过 record 基本知识,record 会实现基于值的类型比较,最近遇到的几个问题觉得用 record 来解决会非常方便,分享一下

    基于值的类型比较

    最近有遇到一个场景,需要比较两个 JSON 字符串是否相等,字符串比较简单,就是一个固定值的 Dictionary,或者认为它就是一个简单的 Model,但是 JSON 字符串的的属性顺序可能不同,比如说下面的这个示例:

    {"Id":1, "Name":"Tom"}, {"Name":"Tom", "Id":1},这两个字符串从字符串上来说顺序不同,自然不相等,但是对应的属性的值是相同的,怎么比较方便的进行比较呢,使用 record 可以比较方便进行比较,来看代码:

    record Person(int Id, string Name);
    
    [Fact]
    public void RecordTest()
    {
        var str1 = "{"Id":1, "Name":"Tom"}";
        var p1 = JsonConvert.DeserializeObject<Person>(str1);
    
        var str2 = "{"Name":"Tom","Id":1}";
        var p2 = JsonConvert.DeserializeObject<Person>(str2);
    
        Assert.True(p1 == p2);
        Assert.Equal(p1, p2);
    }
    

    基于值比较的去重

    我们有一个 API 有收到反馈说,调用多次返回的结果不同,于是我就想写一段代码调用个一百次看是否会有重复,大致代码如下:

    public record Result
    {
        public string Data { get; set;}
        public int Code { get; set; }
    }
    
    var i = 100;
    var results = new HashSet<Result>();
    using var httpClient = new HttpClient();
    while(i-- > 0)
    {
        var responseText = await httpClient.GetStringAsync("");
        var result = JsonConvert.DeserializeObject<Result>(responseText);
        results.Add(result);
    }
    Console.WriteLine(results.Count);
    

    因为 record 不仅会重写 Equals 方法还会重写 GetHashCode 方法,所以可以使用 HashSet 或者 Dictionary 来实现去重

    对象克隆

    record 提供了 with 表达式来方便的克隆一个新的对象,所以在需要克隆的时候可以考虑使用 record,另外所有原型模式的地方都可以考虑使用 record 来实现

    之前我实现了一个简单的日志框架,有一个日志对象,定义如下:

    public class LogHelperLoggingEvent : ICloneable
    {
        public string CategoryName { get; set; }
    
        public DateTimeOffset DateTime { get; set; }
    
        public string MessageTemplate { get; set; }
    
        public string Message { get; set; }
    
        public LogHelperLogLevel LogLevel { get; set; }
    
        public Dictionary<string, object> Properties { get; set; }
    
        public LogHelperLoggingEvent Copy() 
        {
            var newEvent = new LogHelperLoggingEvent()
            {
                CategoryName = CategoryName,
                DateTime = DateTime,
                MessageTemplate = MessageTemplate,
                Message = Message,
                LogLevel = LogLevel
            };
            if (Properties != null)
            {
                newEvent.Properties = new Dictionary<string, object>();
                foreach (var property in Properties)
                {
                    newEvent.Properties[property.Key] = property.Value;
                }
            }
            return newEvent;
        }
    }
    

    我们可以使用 MemberwiseClone 做一个简化

    public class LogHelperLoggingEvent : ICloneable
    {
        public string CategoryName { get; set; }
    
        public DateTimeOffset DateTime { get; set; }
    
        public string MessageTemplate { get; set; }
    
        public string Message { get; set; }
    
        public LogHelperLogLevel LogLevel { get; set; }
    
        public Dictionary<string, object> Properties { get; set; }
    
        public LogHelperLoggingEvent Copy()
        {
            var newEvent = (LogHelperLoggingEvent)MemberwiseClone();
            if (Properties != null)
            {
                newEvent.Properties = new Dictionary<string, object>();
                foreach (var property in Properties)
                {
                    newEvent.Properties[property.Key] = property.Value;
                }
            }
            return newEvent;
        }
    }
    

    使用了 record 之后如下,with 表达式返回的是强类型的对象,不再需要自己做强制类型转换了,上面的做法还是比较取巧的办法,使用了 MemberwiseClone 去做复制,如果自己写代码一个一个复制,将会更加繁琐,使用 record 之后就很简单了,只是我们需要注意一下,with 表达式也只是浅复制,如果内部包含复杂引用类型,需要小心使用

    public record LogHelperLoggingEvent
    {
        public string CategoryName { get; set; }
    
        public DateTimeOffset DateTime { get; set; }
    
        public string MessageTemplate { get; set; }
    
        public string Message { get; set; }
    
        public LogHelperLogLevel LogLevel { get; set; }
    
        public Dictionary<string, object> Properties { get; set; }
    
        public LogHelperLoggingEvent Copy()
        {
            var newEvent = this with{ };
            if (Properties != null)
            {
                newEvent.Properties = new Dictionary<string, object>();
                foreach (var property in Properties)
                {
                    newEvent.Properties[property.Key] = property.Value;
                }
            }
            return newEvent;
        }
    }
    

    More

    record 在很多场景下能够简化我们的代码,使得代码更加干净简洁,在合适的场景下不要忘记使用哦~

    微软的反向代理项目 YARP 也使用了 record 来简化原来代码中 DeepClone 的功能,可以参考 PR:https://github.com/microsoft/reverse-proxy/pull/662

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    maxsdk sample中3dsexp.rc点不开并提示specstrings.h中找不到sal.h解法
    安装max plugin wizard
    max plugin wizard,project creation faild解法
    unity, 由5.2.1f1升级到5.3.5f1,2d物理不正常解法
    maxscript,#号和$号
    maxscript,执行选中代码片段
    maxscript,MAXScript Listener下输入print "hi"为什么输出两次
    editplus查找替换的正则表达式应用
    命令行创建畸形文件夹+畸形目录管理工具(DeformityPath)
    费曼技巧——高速学习的方法
  • 原文地址:https://www.cnblogs.com/weihanli/p/14347769.html
Copyright © 2020-2023  润新知