首页 > 解决方案 > 将 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;
        }
    }
}

理想情况下,这将类似于Fileinfoclass。可以通过提供单个文件名或文件名列表来初始化此类。我还希望能够Person使用全名列表或单个名称来初始化这个类。

标签: c#constructor

解决方案


我不认为这FileInfo门课按你期望的方式工作——但我现在明白你在问什么。如评论中所述,您将需要两个课程。第一个是针对您的业务对象的——在本例中是Person. 第二个是基于集合的类,例如PersonCollection.

作为替代方案,您可以更改数据模型,以便拥有单独的OrganizationPerson类。在该模型中,您的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;
    }
}

笔记

  • 我使用了自动实现的属性语法Organizationand FullName; 否则,它们将被视为公共字段,它们的语义略有不同(来源)。
  • 我已将您的参数名称更新为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[]数组的构造函数的重载以提供更大的灵活性。

推荐阅读