gpt4 book ai didi

c# - 枚举名称的优先级

转载 作者:行者123 更新时间:2023-11-30 14:59:38 26 4
gpt4 key购买 nike

给定以下枚举:

[Flags]
public enum Intervals
{
Root = PerfectUnison,
Unison = PerfectUnison,
PerfectUnison = 1 << 0,
AugmentedUnison = MinorSecond,

MinorSecond = 1 << 1,
Second = MajorSecond,
MajorSecond = 1 << 2,
AugmentedSecond = MinorThird,

MinorThird = 1 << 3,
Third = MajorThird,
MajorThird = 1 << 4,
AugmentedThird = PerfectFourth,
DoubleAugmentedThird = Triton,

DiminishedFourth = MajorThird,
Fourth = PerfectFourth,
PerfectFourth = 1 << 5,
AugmentedFourth = Triton,
DoubleAugmentedFourth = PerfectFifth,

Triton = 1 << 6,

//...Removed for brevity, see link to code bellow
}

我正在尝试这个简单的测试:

static void Main(string[] args)
{
var values = Enum.GetValues(typeof(Intervals));
foreach (var value in values)
{
Console.WriteLine(value);
}
}

这是输出:

PerfectUnison, PerfectUnison, PerfectUnison, AugmentedUnison, AugmentedUnison, Second, Second, MinorThird, MinorThird, DiminishedFourth, DiminishedFourth, DiminishedFourth, AugmentedThird, AugmentedThird, AugmentedThird, AugmentedThird, DoubleDiminishedSixth, DoubleDiminishedSixth etc.

虽然我希望为相同值选择的枚举名称具有以下顺序:

Root, MinorSecond, Second, MinorThird, Third, Fourth, Triton, Fifth, MinorSixth, Sixth, MinorSeventh, Seventh, Octave, MinorNinth, Ninth, Tenth, Eleventh, MajorEleventh, Thirteen

Enum.GetNames 也是一个很好的复制品。我希望上述组的名称始终位于其值匹配名称之前。

我基本上是在寻找每个值的枚举名称的优先级/优先级规则的文档。

您可以使用此处的代码:http://rextester.com/EJOWK87857 .

更新

我现在正在研究反编译的 Enum.GetNames。看起来它使用反射。那么问题来了,“如何控制反射场的顺序?”。

最佳答案

如果不使用元数据,这是不可能的,因为编译器可能会将常量值分配给每个枚举成员。检查编译后的 IL 表明在编译代码时赋值信息丢失了:

.field public static literal valuetype .../Intervals Unison = int32(1)    
.field public static literal valuetype .../Intervals PerfectUnison = int32(1)
.field public static literal valuetype .../Intervals AugmentedUnison = int32(2)
...

由于此信息在编译源代码时会丢失(或者至少不保证可用),因此无法根据运行时的分配分配优先级规则。此限制与 Enum.ToString() 的文档一致,该文档指出如果多个名称与同一值相关联,则选择的成员是不确定的:

If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return.

这就是说,一个可能的解决方法是将属性值分配给被认为是分配优先级的枚举值。例如:

[AttributeUsage(AttributeTargets.Field)]
class PriorityAttribute : Attribute { }
[Flags]
public enum Intervals
{
Root = PerfectUnison,
Unison = PerfectUnison,
[Priority]
PerfectUnison = 1 << 0,
AugmentedUnison = MinorSecond,

[Priority]
MinorSecond = 1 << 1,
Second = MajorSecond,
[Priority]
MajorSecond = 1 << 2,
AugmentedSecond = MinorThird,
...

由于属性信息在运行时与枚举值相关联,所以在运行时可以访问标记的枚举名称:

typeof(Intervals)
.GetFields()
.Where(a => a.GetCustomAttributes(typeof(PriorityAttribute), false).Length > 0)
.Select(a => a.Name))

同样,您可以编写一个类似于 Enum.GetName 的类比,以仅返回具有已定义属性的名称(例如,GetPriorityName(typeof(Intervals), 1) 将始终返回 PerfectUnison

static string GetPriorityName(Type enumType, object v)
{
Type ut = Enum.GetUnderlyingType(enumType);
var pty = enumType.GetFields()
.Where(
a => a.IsLiteral
&& a.GetRawConstantValue().Equals(v)
&& a.GetCustomAttributes(typeof(PriorityAttribute), false).Length > 0
)
.FirstOrDefault();
if (pty == null)
return Enum.GetName(enumType, v); // default to standard if no priority defined
return pty.Name;
}

关于c# - 枚举名称的优先级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16503340/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com