用C#记录封装数据以外的对象合适吗?
Is it appropriate to use C# records for encapsulating objects other than data?
记录非常适合封装数据,但是服务和存储库之类的东西呢? ? 属性 定义的位置语法比 class 定义代码更简洁,因为构造函数、属性和 属性 初始化代码是由编译器为我们生成的。
这里有一个人为的例子来演示。目的是在更少的代码行中使 RecordService
的依赖关系不可变。在真实场景中,依赖项将由服务容器注入。
namespace RecordsTest;
class MyRepo
{
public string SomeMethod() => "MyRepo.SomeMethod()";
}
class MyService
{
public string SomeMethod() => "MyService.SomeMethod()";
}
record RecordService(MyRepo Repo, MyService Service)
{
public void SomeMethod() =>
Console.WriteLine($"RecordService.SomeMethod() {Repo.SomeMethod()} {Service.SomeMethod()}");
}
class Program
{
static void Main(string[] args)
{
var myRepo = new MyRepo();
var myService = new MyService();
var recordService = new RecordService(myRepo, myService);
recordService.SomeMethod();
Console.ReadKey();
}
}
记录提供以下功能(source)
- 创建具有不可变属性的引用类型的简明语法
- 对以数据为中心的引用类型有用的内置行为:
- 价值观平等
- 非破坏性突变的简洁语法
- 显示的内置格式
- 支持继承层次结构
您的示例仅真正受益于构造语法,但这使得声明的属性 public。在编写服务时,这通常不是您想要的。而且,如果您明确指定属性,您几乎不会从使用记录中获得任何好处。
因此,我通常建议在描述数据时使用记录,而对于服务或其他侧重于功能而非数据的代码,则使用常规 类。但我希望在合适的地方会有一些重叠。
记录非常适合封装数据,但是服务和存储库之类的东西呢? ? 属性 定义的位置语法比 class 定义代码更简洁,因为构造函数、属性和 属性 初始化代码是由编译器为我们生成的。
这里有一个人为的例子来演示。目的是在更少的代码行中使 RecordService
的依赖关系不可变。在真实场景中,依赖项将由服务容器注入。
namespace RecordsTest;
class MyRepo
{
public string SomeMethod() => "MyRepo.SomeMethod()";
}
class MyService
{
public string SomeMethod() => "MyService.SomeMethod()";
}
record RecordService(MyRepo Repo, MyService Service)
{
public void SomeMethod() =>
Console.WriteLine($"RecordService.SomeMethod() {Repo.SomeMethod()} {Service.SomeMethod()}");
}
class Program
{
static void Main(string[] args)
{
var myRepo = new MyRepo();
var myService = new MyService();
var recordService = new RecordService(myRepo, myService);
recordService.SomeMethod();
Console.ReadKey();
}
}
记录提供以下功能(source)
- 创建具有不可变属性的引用类型的简明语法
- 对以数据为中心的引用类型有用的内置行为:
- 价值观平等
- 非破坏性突变的简洁语法
- 显示的内置格式
- 支持继承层次结构
您的示例仅真正受益于构造语法,但这使得声明的属性 public。在编写服务时,这通常不是您想要的。而且,如果您明确指定属性,您几乎不会从使用记录中获得任何好处。
因此,我通常建议在描述数据时使用记录,而对于服务或其他侧重于功能而非数据的代码,则使用常规 类。但我希望在合适的地方会有一些重叠。