使用C#9.0记录来构建类似于智能枚举/类似于区分工会/类似于求和类型的数据结构?

问题描述

在C#中使用record类型,看起来像建立区分工会的数据结构可能非常有用,我只是想知道我是否丢失了一些我需要了解的问题。以后会后悔的。例如:

abstract record CardType{
    // Case types
    public record MaleCardType(int age) : CardType{}
    public record FemaleCardType : CardType{}

    // Api
    public static MaleCardType Male(int age) => new MaleCardType(age);
    public static FemaleCardType Female => new FemaleCardType();
}

var w = CardType.Male(42);
var x = CardType.Male(42);
var y = CardType.Male(43);
var z = CardType.Female;
Assert.Equal<CardType>(w,x); //true
Assert.Equal<CardType>(x,y); //false
Assert.Equal<CardType>(y,z); //false

这似乎比用单例和相等比较器以及所有这些构建抽象类要简单得多,但是我是否缺少一些我不想这样做的原因?

解决方法

这是一个很好的方法,我一直在玩它,例如,在 https://fsharpforfunandprofit.com/posts/designing-for-correctness/ 上有一些 C# 代码示例,一些使用类型和可区分联合的 F# 代码,然后一些修改(但仍然很糟糕的 C# 代码)。所以我使用 C# 9s 记录和做 DU 的相同方式重写了 C#

示例代码,比 F# 稍微丑一点,但仍然相当简洁,并具有 F# 代码的优点。

using System;
using System.Collections.Immutable;

namespace ConsoleDU
{
    record CartItem(string Value);

    record Payment(decimal Amount);

    abstract record Cart
    {
        public record Empty () : Cart
        {
            public new static Active Add(CartItem item) => new(ImmutableList.Create(item));
        }
        public record Active (ImmutableList<CartItem> UnpaidItems) : Cart
        {
            public new Active Add(CartItem item) => this with {UnpaidItems = UnpaidItems.Add(item)};
            public new Cart Remove(CartItem item) => this with {UnpaidItems = UnpaidItems.Remove(item)} switch
            {
                var (items) when items.IsEmpty => new Empty(),{ } active => active
            };

            public new Cart Pay(decimal amount) => new PaidFor(UnpaidItems,new(amount));
        }
        public record PaidFor (ImmutableList<CartItem> PaidItems,Payment Payment) : Cart;

        public Cart Display()
        {
            Console.WriteLine(this switch
            {
                Empty => "Cart is Empty",Active cart => $"Cart has {cart.UnpaidItems.Count} items",PaidFor(var items,var payment) => $"Cart has {items.Count} paid items. Amount paid: {payment.Amount}",_ => "Unknown"
            });
            return this;
        }

        public Cart Add(CartItem item) => this switch
        {
            Empty => Empty.Add(item),Active state => state.Add(item),_ => this
        };

        public static Cart NewCart => new Empty();

        public Cart Remove(CartItem item) => this switch
        {
            Active state => state.Remove(item),_ => this
        };

        public Cart Pay(decimal amount) => this switch
        {
            Active cart => cart.Pay(amount),_ => this
        };
    }

    class Program
    {
        static void Main(string[] args)
        {
            Cart.NewCart
                .Display()
                .Add(new("apple"))
                .Add(new("orange"))
                .Display()
                .Remove(new("orange"))
                .Display()
                .Remove(new("apple"))
                .Display()
                .Add(new("orange"))
                .Pay(23M)
                .Display();
            ;
        }
    }
}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...