我试图掩盖edi文件中的索引位置...我有一种情况,根据情况,2或3件事可能在索引处。使用枚举隐藏"魔术数字"很酷。并且很惊讶您可以将多个枚举分配给相同的值,如下所示:
public enum Color
{
Red = 1,
Blue = 1,
Green = 1
}
并且编译器对此感到满意。我没想到这会起作用。我不需要回到枚举中,因此我并不担心要回去,但这个闻起来很时髦。为什么CLR允许枚举的多个值,我应该使用结构吗? (结构似乎比枚举更重要,这似乎有效)
答案 0 :(得分:71)
实际上你已经定义了一个结构......在幕后,一个枚举只是一个结构(但它派生自System.Enum),而枚举的值被定义为常量(你可以用ILDASM来验证它)
您的枚举定义转换为以下伪C#代码:
public struct Color : System.Enum
{
public const int Red = 1;
public const int Blue = 1;
public const int Green = 1;
}
上面的代码不会在C#中编译,因为编译器不允许使用显式基类定义结构,但这是它为枚举定义发出的结构。
由于包含具有相同值的多个常量的类型没有问题,因此枚举定义没有问题。
但由于枚举没有唯一值,因此在转换为此枚举时可能会出现问题。 例如,以下两行代码将返回枚举值Red,因为第一个值是任意选择的。
Color color1 = (Color)1;
Color color2 = (Color)Enum.Parse(typeof(Color), "1");
严格来说,枚举值不是红色,它是1,但是当你打印出值时,你会看到红色。
此外,以下布尔值为true,看起来有点奇怪......
// true (Red is Green??)
bool b = Color.Red == Color.Green;
在底线这是完全合法的,但是在你有意义的时候使用它...
以下是我的.NET教程部分的直接链接,该部分讨论了引擎盖下的枚举:http://motti.me/c1E
答案 1 :(得分:18)
这完全合法的C#。从C# Language specification版本4.0,第14.3节:
多个枚举成员可以共享相同的关联值。例子
enum Color { Red, Green, Blue, Max = Blue }
显示一个枚举,其中两个枚举成员 - 蓝色和最大 - 具有相同的 相关价值。
答案 2 :(得分:11)
相同的数值但不同的名称不是别名。它可以是例如
public enum Color
{
DefaultColor = 1,
Red = 1,
Blue = 2
}
在某些情况下可能有意义但不是很多。当您解析值并调用colorValue.ToString()时,您将获得最后一个值作为字符串值返回(在这种情况下为红色)但是您将松开默认颜色的概念,因为它是相同的东西。至少在你建模数据的方式上。如果你想把它分开,可以为不同的东西使用不同的值。
答案 3 :(得分:4)
这是一个完全可以接受的定义:
public enum AllTheThings
{
TheMoney = 1,
TheFreeRides = 1,
TheLieThatYouDenied = 2,
TheCallsYouveBeenMaking = 3,
TheTimesYouveBeenFaking = 4
}
答案 4 :(得分:3)
如果您将每个枚举值视为常量,则有意义。你没有理由不能有两个具有相同值的常量:
public enum MyColor
{
Blue = 2,
Yellow = 3,
Green = 4
BlueAndYellow = 4,
}
与:
相同public enum MyColor
{
Blue = 2,
Yellow = 3,
Green = 4,
BlueAndYellow = Green,
}
基本上你只有两个不同名字的同一个常数。 BlueAndYellow
是Green
的别名。
答案 5 :(得分:2)
需要注意的一件事是,如果您依赖 C# 自动分配枚举值,那么任何别名成员的顺序就变得很重要。考虑以下几点:
public enum Foo
{
Alpha, // 0
Bravo, // 1
Charlie, // 2
Delta, // 3
}
如果您在那里添加别名,它会重置该位置的自动编号:
public enum Foo
{
Alpha, // 0
Bravo, // 1
Charlie, // 2
AlsoBravo = Bravo, // AlsoBravo assigned 1, same as Bravo
Delta, // Delta is now 2, not 3 as you might expect
}
通常这不是问题,因为别名成员直接出现在他们别名的成员之后。这很好,并且按预期工作:
public enum Foo
{
Alpha, // 0
Bravo, // 1
AlsoBravo = Bravo, // AlsoBravo assigned 1, same as Bravo
Charlie, // Continues with 2, as expected
Delta, // 3
}
今天这个问题让我很头疼,因为我有一个枚举,它的成员具有我不想复制的属性,类似于:
public enum AppIcon
{
[IconMapping(Icon.Cogs)] MenuItem_AppSettingsTab, // 0
[IconMapping(Icon.TabRemove)] MenuItem_CloseTab, // 1
RootTab_AppSettings = MenuItem_AppSettingsTab, // 0
[IconMapping(Icon.Cube)] RootTab_Package, // 1 not 3, oops!
}
答案 6 :(得分:1)
此处需要注意的一点是,非唯一值会导致Visual Studio设计器中缺少值和重复值。
public enum MyColor
{
Red= 1,
Green= 1,
Blue= 2
}
如果您在一个可浏览的属性中使用此枚举,您将在设计器中看到绿色,绿色,蓝色,而不是红色,绿色,蓝色。
答案 7 :(得分:1)
枚举的多个成员指向相同的值可能会引起混淆。我在Visual Studio Marketplace上通过一个简单的扩展为此添加了代码修复。
可在此处获得源代码: https://github.com/toreaurstadboss/UniqueEnumValuesAnalyzer
下面显示了我们检测枚举是否有多个具有相同值的成员的部分。安装.NET Compiler SDK(Roslyn)之后,代码将基于带有代码修复(.NET Standard)项目类型的分析器构建。
public override void Initialize(AnalysisContext context)
{
// TODO: Consider registering other actions that act on syntax instead of or in addition to symbols
// See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Analyzer%20Actions%20Semantics.md for more information
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
}
private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
try
{
var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
if (namedTypeSymbol.EnumUnderlyingType != null)
{
var valueListForEnum = new List<Tuple<string, int>>();
//Debugger.Launch();
//Debugger.Break();
var typeResolved = context.Compilation.GetTypeByMetadataName(namedTypeSymbol.MetadataName) ?? context.Compilation.GetTypeByMetadataName(namedTypeSymbol.ToString());
if (typeResolved != null)
{
foreach (var member in typeResolved.GetMembers())
{
var c = member.GetType().GetRuntimeProperty("ConstantValue");
if (c == null)
{
c = member.GetType().GetRuntimeProperties().FirstOrDefault(prop =>
prop != null && prop.Name != null &&
prop.Name.Contains("IFieldSymbol.ConstantValue"));
if (c == null)
{
continue;
}
}
var v = c.GetValue(member) as int?;
if (v.HasValue)
{
valueListForEnum.Add(new Tuple<string, int>(member.Name, v.Value));
}
}
if (valueListForEnum.GroupBy(v => v.Item2).Any(g => g.Count() > 1))
{
var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0],
namedTypeSymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}
}
}
catch (Exception err)
{
Console.WriteLine(err);
}
}
枚举IceCream看起来像这样:
枚举IceCream { 香草= 0, 巧克力= 2 草莓=香草, 桃子= 2 }