【问题标题】:Create an enum similar to the "Name" property of a class创建一个类似于类的“名称”属性的枚举
【发布时间】:2015-06-16 12:38:46
【问题描述】:

我们的团队一直在缓慢地重构代码以实施 SOLID 实践并实施更好的命名约定。我们遇到了一个问题,我们有一个枚举,该枚举当前与我们需要创建的另一个类命名相同——“部门”。

现在,我们有一个代表不同部门的枚举,例如:

Department.HumanResource
Department.InformationTechnology

这使我们能够使用该枚举基于友好名称而不是在以下情况下的基础整数 ID 快速引用部门:

Employee.IsInDepartment(Department.InformationTechnology)

它不是“类型”或“状态”或类似命名枚举的常用方法。我们认为可能是“DepartmentName”之类的东西,但感觉有点奇怪,因为部门类将具有“Name”属性,而这个枚举也应该是 Department 类的一个属性。

我意识到命名是主观的,所以我想提出问题:

我们是否从错误的角度看待这个问题?还有其他我们忽略的方法来实现这一点吗?

【问题讨论】:

  • 实际上,这在我看来确实像部门类型。
  • 您的问题被否决了,因为标题实际上并不能反映您的问题,您的问题可能会更清楚。尝试“创建类似于名称属性的枚举”并更简洁地表达您的问题。
  • 看看微软是如何用 System.Drawing.KnownColor 和 System.Drawing.Color.FromKnownColor 解决这个问题的。我在整个 .NET 框架的许多地方都看到了这一点。它可能会激发一些想法:)
  • 看看我编辑的答案...
  • @Kjata30:我完全忘记了在更改我所问的内容后重命名问题(因为只是命名的主观性)。感谢您指出了这一点。我将重命名这个问题——我很抱歉!

标签: c# enums renaming


【解决方案1】:

由于您提到希望“枚举”成为功能类的表示(但不一定在每次使用引用时都加载类的数据),您可能会考虑这样的方法。这将使代码感觉像一个枚举,像一个类一样工作,但在需要它们之前不会对数据存储进行任何不必要的访问来填充属性。

public class Department
{
  public int ID { get; private set; }

  //follow this pattern for property values that need to be populated from a data store.
  private string name;
  public string Name
  {
     get{ EnsureLoad(); return name; }
     set{ EnsureLoad(); name = value; }
  }

  public static Department HR{ get{ return GetEmptyDepartment( 1 ); } }
  public static Department IT{ get{ return GetEmptyDepartment( 2 ); } }

  private static Department GetEmptyDepartment(int departmentId)
  {
       return new Department()
       {
           ID = departmentId
       };
  }

  private void EnsureLoad()
  {
     //if not loaded
     //lazy load properties using the ID property against the data store.
  }
}

【讨论】:

  • 这类似于我们现在正在做的,实际上,对于“枚举”。由于遗留系统,我们的部门 ID 实际上不是整数,所以我实现了类型安全的枚举模式来制作我们的“枚举”。现在它只有一个私有构造函数,获取它的实例的唯一方法是请求公共属性或将 ID 转换为 Department 类型。您的方法看起来像是我实现的方法和我在 OP 中描述的信息类之间的混合体。
  • 当时似乎可行,尽管仍然值得考虑摆脱枚举以支持类实例,如上所述,因为听起来枚举在类实例之外没有什么意义,因此它是多余的。类的属性/键可以是任何东西,重要的是概念方法。只是一个想法/可能性。
  • 我们喜欢您建议的技术,并决定取消枚举。我喜欢支持延迟加载的想法——我担心的是我不希望类知道如何查询数据库或与负责查询数据库的类强耦合。我们将创建一个负责这部分的 DepartmentRepository 类。您对此有什么想法或建议使用的资源吗?谢谢!
  • 酷!在这种情况下,我对紧耦合的看法是,如果您将来没有实际理由更换数据访问提供程序,它可以说是一个可以接受的折衷方案。如果 EnsureLoad() 调用 Repository.Load(this) 即使没有物理分离,您也将实现职责的逻辑分离。您可以交替地通过服务定位器模式发现数据访问提供者,或者引发由加载器类或其他东西侦听的 RequestLoad 事件,但这样做可能会矫枉过正,并增加了太多的复杂性而没有得到什么好处。
【解决方案2】:

在所有这些情况下(它会弹出很多,虽然你的例子有很大的缺陷)我通常将枚举命名为<thing>Type,或者在你的情况下为DepartmentType。可以争论它是否 100% 正确,但它很容易理解重点。

至于为什么会有缺陷,实际的部门列表应该来自数据库,因为这个列表会随着时间的推移而演变。您不希望每次在企业中添加新部门时都重新编译项目。

【讨论】:

  • 后一段似乎是一个假设。如果 OP 知道部门不太可能经常更改,那么通过传入枚举值而不是字符串(实际上可以是无限范围的无效值),代码实际上更具可读性、可发现性并且可能更不容易出错。跨度>
  • 不会是字符串,而是整数键,是部门表的外键。
  • 这在可读性和可发现性方面会更糟。部门 2 是什么意思?你不知道! “人力资源”是什么意思?你知道,但不能保证它是一个有效的值(例如,也许你的意思是“人力资源”),如果不知道数据库中的可用选项,你就无法确定什么是有效的。相比之下,Department.HumanResources 的含义很明显,并且很容易通过枚举的智能感知来判断可用的有效选项是什么。
  • 其实我可以查一下,问任何人 5020 是什么部门,它在我们的工资单上。同样在我们所有的数据库、报告和所有内容中。关于你的枚举值,我不能说太多。
  • 如果我作为贵公司的新开发人员不熟悉您的业务和代码(或者如果我记性不好,我会这样做),我不知道 5020 是什么意思。鉴于您发布的信息,我仍然没有。但是,如果我让您在代码中使用 Department.HumanResources,您就知道这意味着什么,而无需我解释任何事情,因为代码是自我记录的。无需记忆数据库密钥。
【解决方案3】:

在你的类中使用常量:

public class Department
{

     //Property to hold the department ID
     public int DepartmentID{ get; set; }

     public const int HumanResources = 1;
     public const int InformationTechnology = 2;
     //And so on..

}

如果 Employee.IsInDepartment 需要一个 int,您可以使用:

Employee.IsInDepartment(Department.HumanResources)...

【讨论】:

  • enum 完成完全相同的事情。
  • 是的,但是他不能有一个枚举和一个同名的类,这是这里的目标......
  • 所以重命名枚举。无需重新发明轮子。
  • 这是用户明确不想要的
【解决方案4】:

对不起,这是 DepartmentType,也是命名约定中最佳实践的方法,无论您喜欢与否,您都有一个具体的类,如果您想遵循最佳实践,则必须将其命名为 Department,这给我们留下了枚举必须是 DepartmentType 遵循命名约定的最佳实践,所以既然你需要类和枚举,我会这样实现它:

创建枚举:

public enum DepartmentType {IT, HR,..... }

在 Department 类中,将该 Enum 也添加为属性:

public Class Department
{
  public Name {get;set;}
  .
  .
  .

  public DepartmentType {get;set;}

}

现在,无论您有部门对象还是想在任何方法中将其作为普通对象,您都可以使用 DepartmentType 枚举。

编辑

另一种方法是摆脱 Enum 并在您的部门类中创建静态 int 值:

   public class Department
    {
       Public string Name {get;set;}
       ...
       ...
       ...
       public static readonly int IT = 1;
       public static readonly int HR = 2;
     }

所以现在您可以将其用作 Department.ITDepartment.HR .....,而无需实例化 Department 类的对象,简而言之,它就像 Enum 一样使用。

【讨论】:

    【解决方案5】:

    这取决于。您希望通过enum 完成什么?如果您希望关闭不同的部门类型,而不管部门的名称是什么,那么使用enum DepartmentType 就非常有意义。例如:

    if (department.Name == "Information Technology")
    

    如果您的 IT 部门的名称已更改,但您仍想对该部门执行相同的操作,这可能会很糟糕。然而,

    if (department.Type == DepartmentType.InformationTechnology)
    

    不在乎部门的名称是什么;只要它代表 IT 部门,您的应用程序就仍然有效。

    此外,如其他答案中所述,如果您希望唯一标识您真正想要使用其主键的部门。您仍然可以通过将 static readonly 字段分配给您的类来获得代码的可读性:

    public static readonly int InformationTechnology = 1;
    

    让您无需明确引用数字即可访问 ID:

    if (department.Id = Department.InformationTechnology)
    

    虽然这种方法的缺点是,如果您想继续检查而不使用魔术整数,则在添加新的 Id 时仍然必须重新编译代码。

    【讨论】:

      猜你喜欢
      • 2022-01-09
      • 1970-01-01
      • 2023-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-01
      • 2020-04-07
      • 2021-08-04
      相关资源
      最近更新 更多