Notification texts go here Contact Us Buy Now!

How can I create a value type with validated construction?

Creating a Value Type with Validated Construction

In C#, creating immutable value types with validated construction can be challenging due to the shallow nature of immutability in the language. Exposing arrays on public surfaces can lead to unintended modifications.

One approach involves using a record class and exposing the data property as an immutable type, such as IReadOnlyList<byte>. This prevents direct modification of the array's contents, but it still allows for scenarios where the array reference can be mutated.

public record CanFrame
{
    public int Id { get; init; }

    public IReadOnlyList<byte> Data { get; init; }

    public CanFrame(int id, byte[] data)
    {
        if (data.Length > 8) throw new ArgumentOutOfRangeException();

        Id = id;
        Data = data;
    }
}

To further restrict mutability, properties can be set as get-only, as seen in the following example:

public record CanFrame
{
    public int Id { get; }

    public IReadOnlyList<byte> Data { get; }

    public CanFrame(int id, byte[] data)
    {
        if (data.Length > 8) throw new ArgumentOutOfRangeException();

        Id = id;
        Data = data;
    }
}

This approach provides immutability, but it lacks the value type semantics and the associated default parameterless constructor.

An alternative approach is to represent the data in a different manner, utilizing an indexer for byte-level access and keeping the data internally as a ulong. This approach ensures complete immutability and provides an efficient representation in memory.

public struct CanFrame
{
    private readonly ulong data;

    public int Id { get; }
    public int Length { get; }

    public byte this[int index]
    {
        get { /* implementation */ }
    }
    public void CopyTo(Span<byte> buffer)
    {
        // Implementation
    }

    public CanFrame(int id, byte[] data)
    {
        // Length validation and conversion of the byte array
        // into a ulong via shifting
    }

    // Potentially other constructors, maybe accepting a ReadOnlySpan<byte>
    // or even a ulong and length
}

This approach provides a fully immutable value type with a reasonable default value and efficient memory usage.

Ultimately, the choice of approach depends on the specific requirements and trade-offs for the given scenario.

Post a Comment

Cookie Consent
We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.
Oops!
It seems there is something wrong with your internet connection. Please connect to the internet and start browsing again.
AdBlock Detected!
We have detected that you are using adblocking plugin in your browser.
The revenue we earn by the advertisements is used to manage this website, we request you to whitelist our website in your adblocking plugin.
Site is Blocked
Sorry! This site is not available in your country.