Ram*_*ein 3 c# enums code-analysis
规则CA1008指定所有枚举都应该有一个0应该命名的值Unknown(我们在这里不讨论标志)。我理解您想要防止未初始化的值自动获得含义的原因。假设我定义了以下枚举:
enum Gender
{
Male,
Female
}
class Person
{
public string Name { get; set; }
public Gender Gender { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这指定了每个人都应该是男性或女性(让我们暂时忽略性别讨论)。如果我忘记设置Gender属性,则此人自动为男性,这可能会导致问题。出于这个原因,我理解 CA1008 警告,因此 0 值应该保留给未知/未初始化的值。
因此,让我们将Gender枚举更改为不再使用 0 值:
enum Gender
{
Male = 1,
Female = 2
}
Run Code Online (Sandbox Code Playgroud)
当我不指定性别时,那么这个人就不是男性或女性。序列化过程中可能会出现问题。该值0对于调试期间的枚举不是很具有描述性。为了修复它并避免 CA1008 警告,我再次更改枚举:
enum Gender
{
Unknown = 0,
Male = 1,
Female = 2
}
Run Code Online (Sandbox Code Playgroud)
未初始化的属性现在显示为Unknown看起来不错。但是我可能引入了另一个问题,那就是该Unknown值看起来像一个有效值并且可以应用于用户。我也可能会收到有关不处理所有枚举值的警告。假设,我使用的构造函数要求我指定性别和名称以避免未初始化的属性:
public Person(string name, Gender gender)
{
Name = name ?? throw new ArgumentNullException(name);
Gender = gender;
}
Run Code Online (Sandbox Code Playgroud)
当我定义Unknown枚举时,我现在可以明确地将性别设置为Unknown. 当然,这可以在构造函数中检查,但这只会在运行时发出信号。当该Unknown值未定义时,调用者只能将其设置为男性或女性。
解决方法可能是使用可为空的性别属性,因此未初始化的值是一个显式null值(我们不再定义该Unknown值)。但是使用可空类型会使编程更加复杂,所以我不建议这样做。
将ObsoleteAttribute应用于该Unknown值可能是一个好主意。当有人明确使用该值时,它会被标记为警告(在构建时)。
处理未初始化的枚举值的正确方法是什么,是使用ObsoleteAttribute一个好主意还是有其他缺点?
注意: * 虽然 obsolete 在这里不是正确的语义,但如果使用该值,它是生成警告的唯一(简单)方法。* 在没有默认构造函数的情况下使用 POCO 可能会使序列化复杂化,因此拥有(可序列化的)类通常是一个坏主意。
使用 ObsoleteAttribute 是个好主意吗?
不。[Obsolete]用于……等待……将过时的成员标记为过时。这是 的唯一正确用法[Obsolete]。不要去为现有的词发明新的含义;这只会造成混乱。
处理未初始化的枚举值的正确方法是什么?
那是错误的问题。退后一步。让我们看一下您问题的大图:
现在你被困住了,不知道该怎么办。
你要做的是:回到第一步到第三步,做出不同的决定。
假设我们重新审视决策 3。您已经确定了每种解决方案的一系列优缺点。决定对于其中之一,利大于弊,然后继续。
假设我们重新审视决定 2。您违反了一系列准则。指南不是规则。您可以确定这些准则对于您的场景是不好的建议,记录您故意违反它们的事实以及原因,抑制警告,然后继续。
假设我们重新审视决定 1。你是那个决定性别最好用枚举表示的人,而且这个决定似乎从那以后给你带来了相当大的痛苦。所以拒绝这个决定:
abstract class Gender :
whatever interfaces you need for serialization and so on
{
private Gender() { } // prevent subclassing
private class MaleGender : Gender
{
// Serialization code for male gender
}
public static readonly Gender Male = new MaleGender();
// now do it all again for FemaleGender
}
Run Code Online (Sandbox Code Playgroud)
我们得到了什么?我们得到了Gender.Male和Gender.Female以前一样,它们和以前一样可序列化,并且任何类型的Gender值要么是男性,要么是女性,要么是空。不喜欢空值?抛出一个异常,就像你得到一个空字符串的人名一样。想要添加更多性别,例如“未知”或“非二进制”或其他什么?添加新的子类型和静态字段。
您不会被迫使用枚举。如果满足枚举的准则让您烦恼,请停止使用枚举。