淺析 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM