c# - 将 C# 类修改为集合
问题描述
下面是一Person
节课。目前,它只能用于实例化单个Person
对象。我想更改它,以便它可以接受全名列表并生成Person
对象集合。
using System;
namespace Test
{
public class Person
{
public string FullName;
public string Organization;
public Person(string Organization, string FullName)
{
this.FullName = FullName;
this.Organization = Organization;
}
}
}
理想情况下,这将类似于Fileinfo
class。可以通过提供单个文件名或文件名列表来初始化此类。我还希望能够Person
使用全名列表或单个名称来初始化这个类。
解决方案
我不认为这FileInfo
门课按你期望的方式工作——但我现在明白你在问什么。如评论中所述,您将需要两个课程。第一个是针对您的业务对象的——在本例中是Person
. 第二个是基于集合的类,例如PersonCollection
.
作为替代方案,您可以更改数据模型,以便拥有单独的Organization
和Person
类。在该模型中,您的Person
类将具有FullName
属性,但没有Organization
属性。我将在最后解决该选项。
我将尝试解释这些概念,而不只是提供代码,同时还会标记您在此过程中可能会遇到的问题。这使得帖子更长。但鉴于问题的性质,我希望这个额外的细节将证明是有价值的。
业务对象
您的Person
班级可以继续按照您建议的方式进行操作。也就是说,您可能会考虑一些改进。
首先,如果您的业务对象在实例化后永远不会被修改(即它是不可变的),那么您可以使用 C# 9.0 记录语法,它允许您的构造函数直接定义属性:
public record Person(string Organization, string FullName);
或者,如果您希望将其保留为一个类,那么我建议您按如下方式实现它:
public class Person
{
public string Organization { get; set; }
public string FullName { get; set; }
public Person(string organization, string fullName)
{
Organization = organization;
FullName = fullName;
}
}
笔记
- 我使用了自动实现的属性语法
Organization
andFullName
; 否则,它们将被视为公共字段,它们的语义略有不同(来源)。 - 我已将您的参数名称更新为
camelCase
,因此您无需使用this
前缀分配属性值。这是 C# 中的标准。 - 我认为
fullName
作为你的第一个参数更直观,但这是一种风格偏好,所以我保持与你的原始代码一致。
基于集合的类
有多种方法可以创建强类型的基于集合的类。最简单的方法是简单地继承自Collection<Person>
:
public class PersonCollection: Collection<Person>
{
public PersonCollection(params Person[] people)
{
foreach (var person in people)
{
Add(person);
}
}
}
笔记
- 您也可以调用 this
People
,就像我在评论中所做的那样,但 Microsoft 建议强类型集合类以项目类型 (ie,Person
) 开头并以Collection
( source ) 结尾。 - 您也可以从 eg, 派生
List<Person>
,但 Microsoft 建议使用更熟悉的Collection<>
类 ( source )。 params
关键字允许您接受一个数组——在这种情况下是Person
对象——但将它们作为参数列表而不是数组(详细信息)传递。在这种情况下,这使得界面更加友好和直观。- 您可以改为接受一个字符串数组——例如,
fullNames
——以便Person
按照您的要求为每个字符串构造一个新对象。但是由于您当前的Person
对象也需要一个Organization
参数,因此首先构造Person
对象,然后将其传递给集合会更容易。
用法
您现在可以通过创建一些Person
实例并将它们传递给PersonCollection
构造函数来构造类,如下所示:
//Construct some Person objects
var robert = new Person("Robert, Inc.", "Robert");
var jeremy = new Person("Ignia, LLC", "Jeremy")
//Construct a new PersonCollection
var people = new PersonCollection(robert, jeremy);
或者,如果您使用 C# 9.0(例如,使用 .NET 5+)并且对Person
初始化程序进行硬编码,您还可以使用以下语法简写:
var people = new PersonCollection(
new ("Robert, Inc.", "Robert"),
new ("Ignia, LLC", "Jeremy")
);
这看起来类似于您传递全名列表的请求——除了它说明您的Organization
财产,并Person
为每个人生成一个完整的对象。如果您真的希望只传入一组名称,请参阅此答案末尾的基于组织的模型。
验证
在实践中,您可能希望添加一些验证以确保每个Person
引用都不为空,并且至少将一个Person
实例传递给您的构造函数。如果是这样,您可以扩展它以包括一些验证。这是一种可能的方法:
public class PersonCollection: Collection<Person>
{
public PersonCollection(params Person[] people)
{
foreach (var person in people?? Array.Empty<Person>())
{
if (person is null)
{
continue;
}
Add(person);
}
if (Count == 0)
{
throw new ArgumentNullException(nameof(people));
}
}
}
我默认使用Array.Empty<Person>
on 循环,这样我们就不需要做两次检查——首先检查people
长度,然后检查PersonCollection
长度。但是您可以根据自己的喜好进行调整。
基于组织的模型
在评论中,您提出了一个替代构造函数:
public People(string Organization, string[] FullName) { … }
这意味着不同的数据模型。如果您要拥有一个可以Person
关联多个 s 的组织,我将改为创建一个Organization
业务对象:
public record Person(FullName);
public class Organization
{
public readonly string Name { get; }
public readonly Collection<Person> Members { get; }
public Organization(string name; params string[] members)
{
Name = name?? throw new ArgumentNullException(nameof(name));
foreach (var memberName in members)
{
Members.Add(new Person(memberName));
}
}
}
笔记
- 在这个模型中,每个
Organization
都有一个Name
,然后是多个Members
——每个都由一个Person
对象表示。 - 因为组织名称是在
Organization
级别处理的,所以大概不需要在每个Person
对象上。 - 如果您只需要名称列表,则可以将
Members
集合替换为 a 。Collection<string>
但是维护一个Person
对象提供了更多的灵活性。 - 您显然也可以将先前提出的验证逻辑合并到此构造函数中。
- 您还可以添加接受
Person[]
数组的构造函数的重载以提供更大的灵活性。
推荐阅读
- javascript - 如何获取更新的在线会员
- java - 为什么我在启动简单代码 (JavaFX) 时遇到问题?
- python - 在pyshark中计算TCP重传
- javascript - 从函数的结果中提取 TImestamp
- node.js - Node JS,快速会话,从客户端浏览器中删除 cookie
- c++ - 无法使用 std::exception 捕获异常
- python - 无法匹配python中的正则表达式模式
- ansible - 有没有办法确定哪些 Ansible 剧本或任务实际上正在使用收集到的事实?
- javascript - 如何检查对象的属性是getter还是setter?
- javascript - 显示微调器 onclick