This article is a mirror article of machine translation, please click here to jump to the original article.

View: 3341|Reply: 0

[Source] .NET/C# new feature record type

[Copy link]
Posted on 10/2/2023 9:25:51 AM | | | |
Starting in C# 9, you can use the record modifier to define a reference type that provides built-in functionality for encapsulating data. C# 10 allows the record class syntax as a synonym to clarify reference types, and allows record struct to define value types using the same functionality.

Use cases for record in C#(ChatGPT answers):

The record type in C# is a new feature introduced in the latest version. It can be used in many scenarios, including but not limited to the following:

Immutable Data Object: The record type is immutable, meaning that once created, its property value cannot be modified. This makes them ideal for representing immutable data structures such as transfer objects (DTOs) or configuration settings.
Value objects: The record type can be used to represent value objects whose equality is determined based on their attribute values rather than reference equivalence. This makes them ideal for comparing and storing value objects such as date ranges, coordinate points, and more.
Pattern Matching: The record type can be used in conjunction with pattern matching, which makes it more convenient when working with complex data structures. You can use pattern matching to check and extract the attribute values of the record object so that you can perform the appropriate action.
Immutable Collections: The record type can be used with immutable collection types such as ImmutableList, ImmutableDictionary, etc., to create immutable collection objects. This ensures that the content of the collection is not modified, thereby improving the reliability and security of the code.
These are just a few of the use cases for the record type, and you can decide whether to use the record type based on your specific needs and code structure.
Difference between record and class and struct

The syntax used when declaring and instantiating a class or structure is the same as when recording an operation. Just replace the class keyword with record, or use record struct instead of struct. Similarly, the record class supports the same syntax for inheritance relationships. The difference between a record and a class is as follows:

  • You can use positional parameters in the main constructor to create and instantiate types with immutable properties.
  • Methods and operators that indicate reference equality or non-equality in classes (e.g., Object.Equals(Object) and ==) indicate value equality or non-equality in the record.
  • You can use the with expression to create a copy of an immutable object with a new value in the selected attribute.
  • The ToString method of the record creates a format string that displays the type name of the object and the names and values of all its common properties.
  • A record can be inherited from another record. But records cannot be inherited from classes, nor can classes be inherited from records.
  • The difference between the record structure and the structure is that the compiler synthesizes methods to determine equality and ToString. The compiler synthesizes the Deconstruct method for the position record structure.


The compiler synthesizes a common initialization-only property for each main constructor parameter in the record class. In a record struct, the compiler synthesizes public read/write properties. The compiler does not create properties for the main constructor arguments in class and struct types that do not contain the record modifier.

record

record class reference type (default: class can be omitted)
record struct value type

record grammar sugar

record is actually thatSyntax sugar, and the final result is class or struct code。 Take the following code as an example:

Finally, it compiles to the following code:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue | DebuggableAttribute.DebuggingModes.DisableOptimizations)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: System.Runtime.CompilerServices.RefSafetyRules(11)]

[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class PersonInfo : IEquatable<PersonInfo>
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly string <FirstName>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly string <LastName>k__BackingField;

    [CompilerGenerated]
    protected virtual Type EqualityContract
    {
        [CompilerGenerated]
        get
        {
            return typeof(PersonInfo);
        }
    }

    public string FirstName
    {
        [CompilerGenerated]
        get
        {
            return <FirstName>k__BackingField;
        }
        [CompilerGenerated]
        init
        {
            <FirstName>k__BackingField = value;
        }
    }

    public string LastName
    {
        [CompilerGenerated]
        get
        {
            return <LastName>k__BackingField;
        }
        [CompilerGenerated]
        init
        {
            <LastName>k__BackingField = value;
        }
    }

    public PersonInfo(string FirstName, string LastName)
    {
        <FirstName>k__BackingField = FirstName;
        <LastName>k__BackingField = LastName;
        base.. ctor();
    }

    [CompilerGenerated]
    public override string ToString()
    {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.Append("PersonInfo");
        stringBuilder.Append(" { ");
        if (PrintMembers(stringBuilder))
        {
            stringBuilder.Append(' ');
        }
        stringBuilder.Append('}');
        return stringBuilder.ToString();
    }

    [CompilerGenerated]
    protected virtual bool PrintMembers(StringBuilder builder)
    {
        RuntimeHelpers.EnsureSufficientExecutionStack();
        builder. Append("FirstName = ");
        builder. Append((object)FirstName);
        builder. Append(", LastName = ");
        builder. Append((object)LastName);
        return true;
    }

    [System.Runtime.CompilerServices.NullableContext(2)]
    [CompilerGenerated]
    public static bool operator !=(PersonInfo left, PersonInfo right)
    {
        return ! (left == right);
    }

    [System.Runtime.CompilerServices.NullableContext(2)]
    [CompilerGenerated]
    public static bool operator ==(PersonInfo left, PersonInfo right)
    {
        return (object)left == right || ((object)left != null && left. Equals(right));
    }

    [CompilerGenerated]
    public override int GetHashCode()
    {
        return (EqualityComparer<Type>. Default.GetHashCode(EqualityContract) * -1521134295 + EqualityComparer<string>. Default.GetHashCode(<FirstName>k__BackingField)) * -1521134295 + EqualityComparer<string>. Default.GetHashCode(<LastName>k__BackingField);
    }

    [System.Runtime.CompilerServices.NullableContext(2)]
    [CompilerGenerated]
    public override bool Equals(object obj)
    {
        return Equals(obj as PersonInfo);
    }

    [System.Runtime.CompilerServices.NullableContext(2)]
    [CompilerGenerated]
    public virtual bool Equals(PersonInfo other)
    {
        return (object)this == other || ((object)other != null && EqualityContract == other. EqualityContract && EqualityComparer<string>. Default.Equals(<FirstName>k__BackingField, other.<FirstName>k__BackingField) && EqualityComparer<string>. Default.Equals(<LastName>k__BackingField, other.<LastName>k__BackingField));
    }

    [CompilerGenerated]
    public virtual PersonInfo <Clone>$()
    {
        return new PersonInfo(this);
    }

    [CompilerGenerated]
    protected PersonInfo(PersonInfo original)
    {
        <FirstName>k__BackingField = original. <FirstName>k__BackingField;
        <LastName>k__BackingField = original. <LastName>k__BackingField;
    }

    [CompilerGenerated]
    public void Deconstruct(out string FirstName, out string LastName)
    {
        FirstName = this. FirstName;
        LastName = this. LastName;
    }
}

namespace Microsoft.CodeAnalysis
{
    [CompilerGenerated]
    [Embedded]
    internal sealed class EmbeddedAttribute : Attribute
    {
    }
}

namespace System.Runtime.CompilerServices
{
    [CompilerGenerated]
    [Microsoft.CodeAnalysis.Embedded]
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
    internal sealed class NullableAttribute : Attribute
    {
        public readonly byte[] NullableFlags;

        public NullableAttribute(byte P_0)
        {
            byte[] array = new byte[1];
            array[0] = P_0;
            NullableFlags = array;
        }

        public NullableAttribute(byte[] P_0)
        {
            NullableFlags = P_0;
        }
    }

    [CompilerGenerated]
    [Microsoft.CodeAnalysis.Embedded]
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
    internal sealed class NullableContextAttribute : Attribute
    {
        public readonly byte Flag;

        public NullableContextAttribute(byte P_0)
        {
            Flag = P_0;
        }
    }

    [CompilerGenerated]
    [Microsoft.CodeAnalysis.Embedded]
    [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
    internal sealed class RefSafetyRulesAttribute : Attribute
    {
        public readonly int Version;

        public RefSafetyRulesAttribute(int P_0)
        {
            Version = P_0;
        }
    }
}
It automatically generates constructors, and rewrites the ToString, GetHashCode, Equals methods, and automatically generates some methods.


p1 and p2 are actually two different objects, but because the compiler automatically generated the comparator (IEquatable) and rewrote the Equals and GetHashCode methods, the output was true. Calling the ToString method is also very intuitive to output the recorded value. As shown below:

.NET/C# implements the IEqualityComparer custom comparator
https://www.itsvse.com/thread-10643-1-1.html



record

required:required modifier indicates that the field or attribute it applies must be initialized by all constructors or using the object initializer. Any expression used to initialize a new instance of that type must initialize all required members.
Reference:The hyperlink login is visible.

init: In C# 9 and later, the init keyword defines the accessor method in a property or indexer. init-only library only assigns values to attributes or indexer elements during object construction. This enforces immutability, so once an object is initialized, it can no longer be changed.
Reference:The hyperlink login is visible.

with: If you need to replicate an instance with some modifications, you can use the with expression to implement non-destructive changes. with expression to create a new record instance that is a copy of an existing record instance, modifying the specified properties and fields.
Reference:The hyperlink login is visible.

So record can be defined as follows:

required, init, not to mention, with is actually syntax sugar, it willCall the automatically generated <Clone>$ methodand then modify the value of the attribute. As follows:



Code:



record attribute

Sometimes we need to add some features to the attributes, such as JSON serialization features, description information, etc.



Resources:

The hyperlink login is visible.
The hyperlink login is visible.





Previous:ASP.NET Core (24) is based on Refit, MemoryPack high-performance communication
Next:GitHub uses the REST API to view repository sizes
Disclaimer:
All software, programming materials or articles published by Code Farmer Network are only for learning and research purposes; The above content shall not be used for commercial or illegal purposes, otherwise, users shall bear all consequences. The information on this site comes from the Internet, and copyright disputes have nothing to do with this site. You must completely delete the above content from your computer within 24 hours of downloading. If you like the program, please support genuine software, purchase registration, and get better genuine services. If there is any infringement, please contact us by email.

Mail To:help@itsvse.com