.net 向上转换然后向下转换一个记录C#

myzjeezk  于 2023-06-07  发布在  .NET
关注(0)|答案(3)|浏览(159)

想象一下下面的记录类

public abstract record Employee
{
  public int EmployeeId {get; init;}
}

---

public record Manager: Employee
{
  public string AdminCode { get; init; }
}

---

public record Trainee : Employee
{
  public int Managerid {get; init; }
}

现在,假设我有一个学员对象,我想用它创建一个管理器对象。当然,我可以一次绘制一个场,但在真实的生活中,我有更大的对象。如果这些是类,这将是一个不入门的,但有整洁的语法,如with,我们可以做一些很酷的事情来创建记录的副本在C#。
我想做什么,但不知道如何(伪代码):

private Boss PromoteTrainee(Trainee trainee, string adminCode)
{
  return (trainee as Employee as Manager) with { AdminCode = adminCode };
}

这当然不起作用,因为第二个as强制转换失败,结果为null。有没有一种方法可以不需要手动复制EmployeeId(以及可能在我的基本对象上的所有其他字段)?

编辑:我认为误导的例子

我的真实的生活中的例子是,我有一堆json合约和DTO对象。许多对象共享一个TON的相同字段(这些字段不会改变,但如果它们改变了,它们总是一起改变),所以我创建了一个基本记录来保存这些字段,这样我就不必在对象之间复制它们。
因为我更喜欢DTO的不可变对象,所以我在属性上使用record类型和init,而不是set。然而,这限制了我的代码只能在创建时使用对象初始化器(或具有其他记录语法的构造函数)来设置属性。
因此,如果我已经有了创建培训生DTO的逻辑,其中包含所有培训生字段和员工基本字段,我如何在不复制大量代码的情况下,将该设置逻辑重新用于Manager DTO,更改设置Manager DTO字段的部分?

snz8szmq

snz8szmq1#

我找到了一个“有效”的解决方案,尽管它可能有点古怪,但它确实解决了我的问题。

public record Manager : Employee
{
    public Manager(Employee fromBase)
    {
        var props = typeof(Employee).GetProperties();
        foreach (var propertyInfo in props)
        {
            propertyInfo.SetValue(this, 
               propertyInfo.GetValue(fromBase));
        }
    }

    public string AdminCode { get; init; }
}

这允许构造Trainee的示例(或者Employee,如果abstract不是必需的),并使用它来构造Manager的示例,其中所有属性都是这样复制的:

var manager = new Manager(trainee){ AdminCode = "1234" };
dgsult0t

dgsult0t2#

如果你使用record,你应该利用位置参数和主构造函数:

public abstract record Employee(int EmployeeId) {
}

public record Manager(int EmployeeID, string AdminCode) : Employee(EmployeeID) {
}

public record Trainee(int EmployeeId, int Managerid) : Employee(EmployeeId) {
}

private Manager PromoteTrainee(Trainee trainee, string adminCode)
    => new Manager(trainee.EmployeeId, adminCode);

如果您在Employee中有很多属性,并且希望避免到处复制它们,那么record可能不是正确的解决方案。您的ManagerTrainee可以与Employee共享一个接口,或者拥有一个包含Employee描述的属性。

bkhjykvo

bkhjykvo3#

作文是一条你可以走的路吗?
试试这个:

public interface IEmployee
{
    int EmployeeId { get; }
}

public record Employee : IEmployee
{
    public int EmployeeId { get; init; }
}

public record Manager : IEmployee
{
    public string AdminCode { get; init; }

    private IEmployee _employee;

    public Manager(IEmployee employee)
    {
        _employee = employee;
    }
    
    public int EmployeeId => _employee.EmployeeId;

    public Trainee Demote(int managerId) =>
        new Trainee(_employee) { ManagerId = managerId};
}

public record Trainee : IEmployee
{
    public int ManagerId { get; init; }

    private IEmployee _employee;

    public Trainee(IEmployee employee)
    {
        _employee = employee;
    }

    public int EmployeeId => _employee.EmployeeId;

    public Manager Promote(string adminCode) =>
        new Manager(_employee) { AdminCode = adminCode };
}

那么你的代码几乎就像你建议的伪代码一样:

Trainee trainee = new Trainee(new Employee() { EmployeeId = 42 })
{
    ManagerId = 101
};
Manager manager = trainee.Promote("AdminCodeHere");

相关问题