提问人:AceGambit 提问时间:6/6/2023 最后编辑:EnigmativityAceGambit 更新时间:6/6/2023 访问量:103
向上投,然后向下投下记录 C#
Upcast and then downcast a record C#
问:
想象一下以下记录类
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; }
}
现在,假设我有一个受训对象,我想从中创建管理器对象。当然,我可以一次绘制一个字段,但在现实生活中,我有更大的对象。如果这些是类,这将是一个不切实际的,但是使用简洁的语法,例如,我们可以做一些很酷的事情来在 C# 中创建记录的副本。with
我想做什么,但不知道该怎么做(pesudo代码):
private Boss PromoteTrainee(Trainee trainee, string adminCode)
{
return (trainee as Employee as Manager) with { AdminCode = adminCode };
}
这当然是行不通的,因为第二次强制转换失败并出现 null。有没有办法做到这一点,不需要手动复制 EmployeeId(以及我的基本对象上可能存在的所有其他字段)?as
**编辑:我认为具有误导性的例子**
我现实生活中的例子是,我有一堆 json 合约和 DTO 对象。许多对象共享大量相同的字段(这些字段不会更改,但如果更改,它们总是会一起更改),因此我创建了一个基本记录来保存这些字段,这样我就不必在对象之间复制它们。
我有因为我更喜欢 DTO 的不可变对象,所以我使用带有 on 属性的类型而不是 .但是,这限制了我的代码,只能在创建时使用对象初始值设定项(或具有其他记录语法的构造函数)设置属性。record
init
set
因此,如果我已经有了创建包含所有受训者字段和员工基本字段的受训者 DTO 的逻辑,那么我如何为经理 DTO 重用该设置逻辑,更改设置经理 DTO 字段的部分,而无需复制大量代码?
答:
我找到了一个“有效”的解决方案,尽管它可能有些骇人听闻,但它确实解决了我的问题。
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)的实例,并使用它来构造 Manager 的实例,并复制所有属性,如下所示:
var manager = new Manager(trainee){ AdminCode = "1234" };
评论
props
GetProperties
如果您使用的是 ,则应利用位置参数和主要构造函数: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);
如果您有很多属性,并且想要避免复制它们,也许不是正确的解决方案。your 和 可以共享接口或具有包含它所描述的 的属性。Employee
record
Manager
Trainee
Employee
Employee
作曲是你可以走的路吗?
试试这个:
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");
评论
record
class
record