我已经阅读了一些SO帖子,似乎缺少最基本的操作.
public enum LoggingLevel
{
Off = 0,
Error = 1,
Warning = 2,
Info = 3,
Debug = 4,
Trace = 5
};
if (s == "LogLevel")
{
_log.LogLevel = (LoggingLevel)Convert.ToInt32("78");
_log.LogLevel = (LoggingLevel)Enum.Parse(typeof(LoggingLevel), "78");
_log.WriteDebug(_log.LogLevel.ToString());
}
Run Code Online (Sandbox Code Playgroud)
这没有例外,它很乐意存储78
.有没有办法验证进入枚举的值?
SwD*_*n81 241
用法:
if(Enum.IsDefined(typeof(MyEnum), value))
MyEnum a = (MyEnum)value;
Run Code Online (Sandbox Code Playgroud)
这是该页面的示例:
using System;
[Flags] public enum PetType
{
None = 0, Dog = 1, Cat = 2, Rodent = 4, Bird = 8, Reptile = 16, Other = 32
};
public class Example
{
public static void Main()
{
object value;
// Call IsDefined with underlying integral value of member.
value = 1;
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with invalid underlying integral value.
value = 64;
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with string containing member name.
value = "Rodent";
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with a variable of type PetType.
value = PetType.Dog;
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
value = PetType.Dog | PetType.Cat;
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with uppercase member name.
value = "None";
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
value = "NONE";
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with combined value
value = PetType.Dog | PetType.Bird;
Console.WriteLine("{0:D}: {1}", value, Enum.IsDefined(typeof(PetType), value));
value = value.ToString();
Console.WriteLine("{0:D}: {1}", value, Enum.IsDefined(typeof(PetType), value));
}
}
Run Code Online (Sandbox Code Playgroud)
该示例显示以下输出:
// 1: True
// 64: False
// Rodent: True
// Dog: True
// Dog, Cat: False
// None: True
// NONE: False
// 9: False
// Dog, Bird: False
Run Code Online (Sandbox Code Playgroud)
jos*_*ley 28
上述解决方案不涉及[Flags]
情况.
我下面的解决方案可能存在一些性能问题(我确信可以通过各种方式进行优化),但实质上它总能证明枚举值是否有效.
它依赖于三个假设:
int
,绝对不允许-
如果没有枚举enum(flag或not),则调用ToString()
enum将返回int
值.如果匹配允许的枚举值,它将打印匹配的名称.
所以:
[Flags]
enum WithFlags
{
First = 1,
Second = 2,
Third = 4,
Fourth = 8
}
((WithFlags)2).ToString() ==> "Second"
((WithFlags)(2 + 4)).ToString() ==> "Second, Third"
((WithFlags)20).ToString() ==> "20"
Run Code Online (Sandbox Code Playgroud)
考虑到这两个规则,我们可以假设,如果.NET Framework正确地完成了它的工作,那么对有效枚举ToString()
方法的任何调用都将导致某个字母字符作为其第一个字符:
public static bool IsValid<TEnum>(this TEnum enumValue)
where TEnum : struct
{
var firstChar = enumValue.ToString()[0];
return (firstChar < '0' || firstChar > '9') && firstChar != '-';
}
Run Code Online (Sandbox Code Playgroud)
人们可以称之为"黑客",但优点是依靠微软自己的Enum
C#标准实现,你不依赖于你自己的潜在错误代码或检查.在性能不是特别关键的情况下,这将节省大量令人讨厌的switch
陈述或其他检查!
编辑
感谢@ChaseMedallion指出我的原始实现不支持负值.这已得到补救并提供了测试.
[TestClass]
public class EnumExtensionsTests
{
[Flags]
enum WithFlags
{
First = 1,
Second = 2,
Third = 4,
Fourth = 8
}
enum WithoutFlags
{
First = 1,
Second = 22,
Third = 55,
Fourth = 13,
Fifth = 127
}
enum WithoutNumbers
{
First, // 1
Second, // 2
Third, // 3
Fourth // 4
}
enum WithoutFirstNumberAssigned
{
First = 7,
Second, // 8
Third, // 9
Fourth // 10
}
enum WithNagativeNumbers
{
First = -7,
Second = -8,
Third = -9,
Fourth = -10
}
[TestMethod]
public void IsValidEnumTests()
{
Assert.IsTrue(((WithFlags)(1 | 4)).IsValid());
Assert.IsTrue(((WithFlags)(1 | 4)).IsValid());
Assert.IsTrue(((WithFlags)(1 | 4 | 2)).IsValid());
Assert.IsTrue(((WithFlags)(2)).IsValid());
Assert.IsTrue(((WithFlags)(3)).IsValid());
Assert.IsTrue(((WithFlags)(1 + 2 + 4 + 8)).IsValid());
Assert.IsFalse(((WithFlags)(16)).IsValid());
Assert.IsFalse(((WithFlags)(17)).IsValid());
Assert.IsFalse(((WithFlags)(18)).IsValid());
Assert.IsFalse(((WithFlags)(0)).IsValid());
Assert.IsTrue(((WithoutFlags)1).IsValid());
Assert.IsTrue(((WithoutFlags)22).IsValid());
Assert.IsTrue(((WithoutFlags)(53 | 6)).IsValid()); // Will end up being Third
Assert.IsTrue(((WithoutFlags)(22 | 25 | 99)).IsValid()); // Will end up being Fifth
Assert.IsTrue(((WithoutFlags)55).IsValid());
Assert.IsTrue(((WithoutFlags)127).IsValid());
Assert.IsFalse(((WithoutFlags)48).IsValid());
Assert.IsFalse(((WithoutFlags)50).IsValid());
Assert.IsFalse(((WithoutFlags)(1 | 22)).IsValid());
Assert.IsFalse(((WithoutFlags)(9 | 27 | 4)).IsValid());
Assert.IsTrue(((WithoutNumbers)0).IsValid());
Assert.IsTrue(((WithoutNumbers)1).IsValid());
Assert.IsTrue(((WithoutNumbers)2).IsValid());
Assert.IsTrue(((WithoutNumbers)3).IsValid());
Assert.IsTrue(((WithoutNumbers)(1 | 2)).IsValid()); // Will end up being Third
Assert.IsTrue(((WithoutNumbers)(1 + 2)).IsValid()); // Will end up being Third
Assert.IsFalse(((WithoutNumbers)4).IsValid());
Assert.IsFalse(((WithoutNumbers)5).IsValid());
Assert.IsFalse(((WithoutNumbers)25).IsValid());
Assert.IsFalse(((WithoutNumbers)(1 + 2 + 3)).IsValid());
Assert.IsTrue(((WithoutFirstNumberAssigned)7).IsValid());
Assert.IsTrue(((WithoutFirstNumberAssigned)8).IsValid());
Assert.IsTrue(((WithoutFirstNumberAssigned)9).IsValid());
Assert.IsTrue(((WithoutFirstNumberAssigned)10).IsValid());
Assert.IsFalse(((WithoutFirstNumberAssigned)11).IsValid());
Assert.IsFalse(((WithoutFirstNumberAssigned)6).IsValid());
Assert.IsFalse(((WithoutFirstNumberAssigned)(7 | 9)).IsValid());
Assert.IsFalse(((WithoutFirstNumberAssigned)(8 + 10)).IsValid());
Assert.IsTrue(((WithNagativeNumbers)(-7)).IsValid());
Assert.IsTrue(((WithNagativeNumbers)(-8)).IsValid());
Assert.IsTrue(((WithNagativeNumbers)(-9)).IsValid());
Assert.IsTrue(((WithNagativeNumbers)(-10)).IsValid());
Assert.IsFalse(((WithNagativeNumbers)(-11)).IsValid());
Assert.IsFalse(((WithNagativeNumbers)(7)).IsValid());
Assert.IsFalse(((WithNagativeNumbers)(8)).IsValid());
}
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*ell 16
规范的答案是Enum.IsDefined
,但这是:如果在紧密循环中使用有点慢,而b:对[Flags]
枚举没用.
就个人而言,我不再担心这一点,只是switch
恰如其分地记住:
default:
(或者说空的default:
解释原因)default:
像这样:
switch(someflag) {
case TriBool.Yes:
DoSomething();
break;
case TriBool.No:
DoSomethingElse();
break;
case TriBool.FileNotFound:
DoSomethingOther();
break;
default:
throw new ArgumentOutOfRangeException("someflag");
}
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题[Flags]
,您还可以使用C# Cookbook 中的解决方案:
首先,ALL
向枚举添加一个新值:
[Flags]
enum Language
{
CSharp = 1, VBNET = 2, VB6 = 4,
All = (CSharp | VBNET | VB6)
}
Run Code Online (Sandbox Code Playgroud)
然后,检查该值是否在ALL
:
public bool HandleFlagsEnum(Language language)
{
if ((language & Language.All) == language)
{
return (true);
}
else
{
return (false);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
51006 次 |
最近记录: |