我有一个CarInfo类,它保存着一辆车及其车主的信息.所有者可以是已知的客户(例如,我们可以查找它并填充Customer类),或者我们只知道客户的名称(在这种情况下,我们不能填充Customer类).我有一个Blazor表单,它公开了carfo类.如何针对Customer信息成员设计这个类,它可以是Customer,也可以只是名字和姓氏?

public CarInfo
{
     public Guid Id { get; }
     ...
     public Customer? { get; set; }           // Either this member can be populated
     public string? FirstName { get; set; }   // or the First- and Last name members.
     public string? LastName { get; set; }
     ...
}

处理这一问题的最佳设计是什么?我是否应该将Customer和名字和姓氏分解到一个新的类中,例如CustomerInfo,并在那里处理这种多态?

public CustomerInfo
{
   public Customer? { get; private set; }
   public string? FirstName { get; private set; }
   public string? LastName { get; private set; }

   public CustomerInfo(Customer customer) => Customer = customer;
   public CustomerInfo(string firstName, string lastName)
   {
      FirstName = firstName;
      LastName = lastName;
   }
}

然后像这样使用它?

public CarInfo
{
    public Guid Id { get; }
    ...
    public CustomerInfo { get; set; }           
    ...
}

我有点纠结于在这里应该参考什么是最好的实践或模式.

推荐答案

在future 的某个时候,我们may会将"Discriminated Unions"添加到C#中.

它们允许您声明一个类型,该类型可能只包含具有一组指定类型之一的项.在您的例子中,唯一允许的类型是Customer,我将称之为CustomerName类型.

在此之前,您可以使用OneOf NuGet package来完成此操作.

您的CarInfo和支持类型可能如下所示:

public class CarInfo
{
    public Guid Id { get; } = Guid.NewGuid();
    public OneOf<Customer, CustomerName> CustomerDetails { get; set; }
}

public record CustomerName(string FirstName, string LastName)
{
}

public record Customer(string  FirstName, string LastName, string Etc /*Other stuff*/)
{
}

然后,您可以使用CustomerNameCustomer来初始化CarInfo.CustomerDetails ,但不能使用其他选项:

public static class Program
{
    public static void Main()
    {
        var carInfo1 = new CarInfo
        {
            CustomerDetails = new Customer("Fred", "Bloggs", "Address")
        };

        var carInfo2 = new CarInfo
        {
            CustomerDetails = new CustomerName("Fred", "Bloggs")
        };
    }
}

当您访问CustomerDetails属性时,您通常需要使用have来说明该属性可能具有的所有类型-这避免了忘记处理所有类型:

carInfo1.CustomerDetails.Switch(
    customer     => Console.WriteLine($"Full customer available: {customer}"),
    customerName => Console.WriteLine($"Only name and address available: {customerName}")
);

carInfo2.CustomerDetails.Switch(
    customer     => Console.WriteLine($"Full customer available: {customer}"),
    customerName => Console.WriteLine($"Only name and address available: {customerName}")
);

请注意,使用OneOf<>可能不是适合您的情况的最佳模型,但它确实符合您的描述.但是,您应该考虑其他可能性,例如对丢失的信息使用可为空的属性.

Csharp相关问答推荐

c#处理大量tcp连接

ASP.NET Core -如何解决Fluent验证中无法访问的扩展方法Message Formatter错误

PostingAsJsonAschange在从调用的方法返回时给出500错误

我可以将Expressc操作设置为在另一个Expressc操作完成后自动发生吗?

System.文本.Json现在总是需要无参数构造函数吗?

Blazor:计算值或保留为默认值

C#相同名称的枚举方法和normal方法,参数类型不同

C#自定义字典与JSON(de—)serialize

解析需要HttpClient和字符串的服务

如何注册实现同一接口的多个服务并注入到控制器构造函数中

为什么无法将对象转换为泛型类型

从VS调试器而不是测试资源管理器运行的调试NUnitDotNet测试

自定义列表按字符串的部分排序

在ASP.NET Core 8 MVC中本地化共享视图

MSI无法将快捷方式添加到启动文件夹

ReadOnlyMemory访问基础索引的替代方案

EF Core:如何对关系属性进行建模?

如何使用实体框架核心对字符串_agg使用强制转换为varchar(Max)

C#静态抽象属性不能被子接口覆盖

为什么C#中的类型别名不能在另一个别名中使用?