我认为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级。
两种情况:
- 喝酒前
- 喝完后
..
public enum ListEnum { CategoryOne, CategoryTwo, CategoryThree, CategoryFour } public class UIELementType { public const string FactoryDomain = "FactoryDomain"; public const string Attributes = "Attributes"; }
使用不反模式的枚举。 在一些关于重构的书中,这段代码用于演示如何用多态替换它。 当你在代码中过度使用枚举时就可以了。
这完全取决于你尝试用枚举做什么。
-
如果您试图阻止开发人员将魔术数字传递到您的操作中,并且您希望保持数据引用完整性与您的数据库完整,那么,是的! 使用T4-Templates(使用您的ORM)转到您的MeasurementUnitTypes表并生成一个枚举,其ID,Name和Description列与枚举’int,Enum_Name和Description属性相匹配(其他字段数据的好方法可以枚举@danijels)如上所述。 如果向MeasurementUnitTypes表中添加新的Measurement Type,则可以右键单击并运行T4-Template,并为表中添加的新行生成枚举代码。 我不喜欢我的应用程序中没有链接到我的数据库的硬编码数据,因此提到了T4模板方法。 它是不可扩展的,否则……如果某个其他外部系统想要检索我们系统中使用的测量标准,那么它在系统中是硬编码的,您不能通过服务将其暴露给客户端。 那就离开了。
-
如果目的不是数据相关的,并且你有一些逻辑分配给特定的枚举,那么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#学习教程,希望大家多多关注—编程笔记