热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#学习教程:C#:Enum反模式分享

C#:Enum反模式有人一直在谈论Enums一般违反清洁代码原则,所以我正在寻找人们最喜欢的Enum反模式和替代解决方案。例如,我见过这样的代码:switch(enumValue)

C#:Enum反模式

有人一直在谈论Enums一般违反清洁代码原则,所以我正在寻找人们最喜欢的Enum反模式和替代解决方案。

例如,我见过这样的代码:

switch(enumValue) { case myEnum.Value1: // ... break; case myEnum.Value2: // ... break; } 

它比带有魔术字符串的switch语句更好一步,但这可能已经通过工厂,容器或其他模式更好地解决了。

甚至像这样的老派代码:

 if(enumValue == myEnum.Value1) { // ... } else if (enumValue == myEnum.Value2) { // ... } 

您对枚举有哪些其他反模式和更好的实现

我认为Enums非常有用。 我为Enum写了一些扩展,为它的使用增加了更多的价值

首先,有Description扩展方法

 public static class EnumExtensions { public static string Description(this Enum value) { var entries = value.ToString().Split(ENUM_SEPERATOR_CHARACTER); var description = new string[entries.Length]; for (var i = 0; i  0) ? attributes[0].Description : entries[i].Trim(); } return String.Join(", ", description); } private const char ENUM_SEPERATOR_CHARACTER = ','; } 

这将允许我像这样定义en enum:

  public enum MeasurementUnitType { [Description("px")] Pixels = 0, [Description("em")] Em = 1, [Description("%")] Percent = 2, [Description("pt")] Points = 3 } 

并通过执行以下操作获取标签: var myLabel = rectangle.widthunit.Description() (不需要switch语句)。

如果rectangle.widthunit = MeasurementUnitType.Pixels ,它将返回“px”,如果rectangle.widthunit = MeasurementUnitType.Pixels ,它将返回“px,em” rectangle.widthunit = MeasurementUnitType.Pixels | MeasurementUnitType.Em

然后,有一个

  public static IEnumerable GetIntBasedEnumMembers(Type @enum) { foreach (FieldInfo fi in @enum.GetFields(BindingFlags.Public | BindingFlags.Static)) yield return (int)fi.GetRawConstantValue(); } 

这将让我遍历任何基于int的值的枚举并返回int值本身。

我发现这些在一个已经很有用的概念中非常有用。

我看到有两个 switch语句作为非OO设计的症状, 如本答案中进一步解释的那样 。

这不是答案,而是对Enum反模式列表的贡献。

在今天早上的代码审查期间,我遇到了类似于以下的案例,所有案例都在同一个class级。

两种情况:

  1. 喝酒前
  2. 喝完后

..

  public enum ListEnum { CategoryOne, CategoryTwo, CategoryThree, CategoryFour } public class UIELementType { public const string FactoryDomain = "FactoryDomain"; public const string Attributes = "Attributes"; } 

使用不反模式的枚举。 在一些关于重构的书中,这段代码用于演示如何用多态替换它。 当你在代码中过度使用枚举时就可以了。

这完全取决于你尝试用枚举做什么。

  1. 如果您试图阻止开发人员将魔术数字传递到您的操作中,并且您希望保持数据引用完整性与您的数据库完整,那么,是的! 使用T4-Templates(使用您的ORM)转到您的MeasurementUnitTypes表并生成一个枚举,其ID,Name和Description列与枚举’int,Enum_Name和Description属性相匹配(其他字段数据的好方法可以枚举@danijels)如上所述。 如果向MeasurementUnitTypes表中添加新的Measurement Type,则可以右键单击并运行T4-Template,并为表中添加的新行生成枚举代码。 我不喜欢我的应用程序中没有链接到我的数据库的硬编码数据,因此提到了T4模板方法。 它是不可扩展的,否则……如果某个其他外部系统想要检索我们系统中使用的测量标准,那么它在系统中是硬编码的,您不能通过服务将其暴露给客户端。 那就离开了。

  2. 如果目的不是数据相关的,并且你有一些逻辑分配给特定的枚举,那么NO! 这违反了SOLID(开放式关闭原则),就像你在应用程序的某个地方应用一个开关或一堆Ifs来操作每个枚举的逻辑一样,如果你这样做真的很糟糕这些开关或者Ifs都在整个节目……祝你好运添加一个新的枚举……所以它不是为了扩展而打开,而是因为你需要修改现有代码而根据SOLID原则关闭修改。

    如果您的选择是2,那么我建议您使用@danijels评论中的示例用以下内容替换您的枚举:

     public interface IMeasurementUnitType { int ID { get; } string Description { get; } // Just added to simulate a action needed in the system string GetPrintMessage(int size); } 

上面的代码定义了每个度量应遵循的接口(代码契约)。 现在让我们定义百分比和像素测量:

  public class PixelsMeasurementUnitType : IMeasurementUnitType { public int ID => 1; public string Description => "Pixel"; public string GetPrintMessage(int size) { return $"This is a {Description} Measurement that is equal to {size} pixels of the total screen size"; } } public class PercentMeasurementUnitType : IMeasurementUnitType { public int ID => 2; public string Description => "Persentage"; public string GetPrintMessage(int size) { return $"This is a {Description} Measurement that is equal to {size} persent of total screen size (100)"; } } 

所以我们定义了两种类型,我们将在代码中使用它们,如下所示:

  var listOfMeasurmentTypes = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => typeof(IMeasurementUnitType).IsAssignableFrom(p) && !p.IsInterface) .ToList(); 

这里我们获取扩展IMeasurementUnitType接口的所有TYPES而不是接口本身。 现在我们可以使用Activator创建类的实例来填充我们的UI控件:

  public IEnumerable GetInstantiatedClassesFromTypes(List types) { foreach (var type in types) { yield return (IMeasurementUnitType)Activator.CreateInstance(type); } } 

您可以将上面的代码更改为任何类型的通用代码,现在生活发生,客户端提供一个名为Point的新测量单位类型作为新要求,我不需要更改任何代码,只需添加新类型(扩展)代码不修改)。 新类型将在应用程序中自动获取。

  public class PointMeasurementUnitType : IMeasurementUnitType { public int ID => 3; public string Description => "Point"; public string GetPrintMessage(int size) { return $"This is a {Description} Measurement that is equal to {size} points of total screen size"; } } 

一个好主意是在启动应用程序时尝试缓存类型以获得性能优势,或者尝试使用您选择的DI容器。

此外,有人可以争辩说,在你的应用程序的某个地方,你需要区分类型,我同意,但是你想要苹果与苹果。 因此,尽可能尝试应用与此类型相同的原则。 如果在某种类型的图形处理器(例如)类中使用此类型,则具有IGraphicsProcessor并具有区分这些类型的具体类,例如PersentageAndPixelGraphicsProcessor(从IGraphicsProcessor扩展),或者如果它仅区分一种类型,则称为PersentageGraphicsProcessor。

很抱歉HUGE SA,但我真的很喜欢enum,但是当我尝试使用枚举分离逻辑时,我觉得它是一个强大的反模式。

欢迎评论,

上述就是C#学习教程:C#:Enum反模式分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—编程笔记


推荐阅读
  • 本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
  • 本文详细介绍了Java中org.w3c.dom.Text类的splitText()方法,通过多个代码示例展示了其实际应用。该方法用于将文本节点在指定位置拆分为两个节点,并保持在文档树中。 ... [详细]
  • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
  • 本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 深入了解 Windows 窗体中的 SplitContainer 控件
    SplitContainer 控件是 Windows 窗体中的一种复合控件,由两个可调整大小的面板和一个可移动的拆分条组成。本文将详细介绍其功能、属性以及如何通过编程方式创建复杂的用户界面。 ... [详细]
  • 本文基于刘洪波老师的《英文词根词缀精讲》,深入探讨了多个重要词根词缀的起源及其相关词汇,帮助读者更好地理解和记忆英语单词。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ... [详细]
author-avatar
圊渘湜壞亾
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有