在JVM/Groovy领域工作了几年后,我最近回到了.NET世界。
我最喜欢的 C# 日常模式之一是 Type-Safe 枚举模式,我觉得它非常方便。回到 C#,我立即开始使用它,但现在我怀疑可能有更好或更可取的模式。
让我思考的是我想在"枚举"中引入一些行为。喜欢这个:
public sealed class TypeSafeEnumWithBehaviour
{
public static readonly TypeSafeEnumWithBehaviour IsLowerCase = new TypeSafeEnumWithBehaviour("IsLowerCase", s => s.All(c => Char.IsLower(c)));
public static readonly TypeSafeEnumWithBehaviour IsUpperCase = new TypeSafeEnumWithBehaviour("IsUpperCase", s => s.All(c => Char.IsUpper(c)));
public readonly string Name;
public readonly Func<string, bool> IsValid;
private TypeSafeEnumWithBehaviour(string targetName, Func<string, bool> validation)
{
Name = targetName;
IsValid = validation;
}
}
测试:
[TestMethod]
public void TestMethod1()
{
Assert.IsTrue(TypeSafeEnumWithBehaviour.IsLowerCase.IsValid("apa"));
Assert.IsTrue(TypeSafeEnumWithBehaviour.IsUpperCase.IsValid("PAPA"));
}
我的组织目前正在使用 C# 6,但 C# 7 变得越来越普遍,这让我想到了几个问题。
- 类型安全枚举模式的当前视图是什么?
- 它仍然是一个有效的模式,特别是关于序列化/持久化?
- 我应该放弃它而选择其他东西吗?
C#(从版本 7.1 开始)不支持总和类型,因此在解决此问题之前,您提供的链接中描述的模式将作为静态检查的近世界变体问题的部分解决方案。可以检查在 F# 中对此的正确语言支持。
你的例子有点奇怪:这些选项并不是真正不同的变体。对于""
,他们都持有,对于"Aa"
他们都没有持有。它们实际上并没有形成不同可能性的集合,因此不清楚为什么称它们为枚举。
与 C# 7 语言创新无关的小吹毛求疵:您应该考虑使用这样的nameof
:
public static readonly TypeSafeEnumWithBehaviour IsLowerCase = new TypeSafeEnumWithBehaviour(nameof(IsLowerCase), s => s.All(c => Char.IsLower(c)));
这取决于您要尝试使用枚举做什么。
在要检查大小写的示例中,也许扩展方法适合,如下所示:
public static bool IsLowerCase(this Enum value)
{
return value.ToString() == value.ToString().ToLower();
}
这将允许您像这样使用它:
SomeEnum value = SomeEnums.Test;
if (value.IsLowerCase())
{
DoSomething();
}
要回答您的问题:
- 类型安全的枚举模式在某些可能不需要扩展方法或其他方法的情况下仍然有效。
- 序列化最好通过属性来完成,但任何实例都需要根据具体情况进行处理 - 提供一揽子建议太笼统了。
- 只有在有明确理由的情况下才放弃它,例如,新的语言功能等。当真正使用任何模式时,这都是正确的。