热门标签 | 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#学习教程,希望大家多多关注—编程笔记


推荐阅读
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • Redux入门指南
    本文介绍Redux的基本概念和工作原理,帮助初学者理解如何使用Redux管理应用程序的状态。Redux是一个用于JavaScript应用的状态管理库,特别适用于React项目。 ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
  • 探讨ChatGPT在法律和版权方面的潜在风险及影响,分析其作为内容创造工具的合法性和合规性。 ... [详细]
  • Python 内存管理机制详解
    本文深入探讨了Python的内存管理机制,涵盖了垃圾回收、引用计数和内存池机制。通过具体示例和专业解释,帮助读者理解Python如何高效地管理和释放内存资源。 ... [详细]
  • C#设计模式学习笔记:观察者模式解析
    本文将探讨观察者模式的基本概念、应用场景及其在C#中的实现方法。通过借鉴《Head First Design Patterns》和维基百科等资源,详细介绍该模式的工作原理,并提供具体代码示例。 ... [详细]
  • 本文介绍了如何在 Node.js 中使用 `setDefaultEncoding` 方法为可写流设置默认编码,并提供了详细的语法说明和示例代码。 ... [详细]
  • HTML5 表单新增属性详解
    本文深入探讨了HTML5中表单的新增属性,帮助读者全面掌握这些新特性。内容涵盖autocomplete、autofocus、list等常用属性,并详细解释了form、novalidate、enctype和accept-charset等高级属性的功能与应用场景。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • 优化SQL Server批量数据插入存储过程的实现
    本文介绍了一种改进的SQL Server存储过程,用于生成批量插入语句。该方法不仅提高了性能,还支持单行和多行模式,适用于SQL Server 2005及以上版本。 ... [详细]
  • 使用JS、HTML5和C3创建自定义弹出窗口
    本文介绍如何结合JavaScript、HTML5和C3.js来实现一个功能丰富的自定义弹出窗口。通过具体的代码示例,详细讲解了实现过程中的关键步骤和技术要点。 ... [详细]
  • MongoDB的核心特性与架构解析
    本文深入探讨了MongoDB的核心特性,包括其强大的查询语言、灵活的文档模型以及高效的索引机制。此外,还详细介绍了MongoDB的体系结构,解释了其文档、集合和数据库的层次关系,并对比了MongoDB与传统关系型数据库(如MySQL)的逻辑结构。 ... [详细]
  • 在尝试从数据库获取设置的过程中,遇到了一个致命错误:Fatal error: Call to a member function bind_param() on boolean。本文将详细分析该错误的原因,并提供解决方案。 ... [详细]
  • 本文将继续探讨前端开发中常见的算法问题,重点介绍如何将多维数组转换为一维数组以及验证字符串中的括号是否成对出现。通过多种实现方法的解析,帮助开发者更好地理解和掌握这些技巧。 ... [详细]
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社区 版权所有