C# 从整数强制转换时,如何定义“捕获所有”枚举值?
我的C#代码中定义了一个枚举类型,该枚举类型与Win32炣NetworkAdapter WMI表中NetConnectionStatus字段的所有可能值相对应,as 文档显示,从0到12的整数都有一个唯一的状态名称,但是13到65535之间的所有整数都集中到一个称为“其他”的存储桶中。因此,我的代码如下:C# 从整数强制转换时,如何定义“捕获所有”枚举值?,c#,enums,C#,Enums,我的C#代码中定义了一个枚举类型,该枚举类型与Win32炣NetworkAdapter WMI表中NetConnectionStatus字段的所有可能值相对应,as 文档显示,从0到12的整数都有一个唯一的状态名称,但是13到65535之间的所有整数都集中到一个称为“其他”的存储桶中。因此,我的代码如下: [Serializable] public enum NetConnectionStatus { Disconnected = 0, Connecting = 1, C
[Serializable]
public enum NetConnectionStatus
{
Disconnected = 0,
Connecting = 1,
Connected = 2,
Disconnecting = 3,
HardwareNotPresent = 4,
HardwareDisabled = 5,
HardwareMalfunction = 6,
MediaDisconnected = 7,
Authenticating = 8,
AuthenticationSucceeded = 9,
AuthenticationFailed = 10,
InvalidAddress = 11,
CredentialsRequired = 12,
Other
}
这适用于非其他值。例如,我可以这样做:
var result = (NetConnectionStatus) 2;
Assert.AreEqual(NetConnectionStatus.Connected, result);
但对于更高数值范围内的任何东西,它的效果都不太好。我希望我能做到这一点:
var result = (NetConnectionStatus) 20;
Assert.AreEqual(NetConnectionStatus.Other, result);
但是现在,
result
变量被分配了文本值20
,而不是Other
。是否有一些现成的方法来实现这一点,类似于Parse()
,但用于整数而不是字符串,或者可能是一些我不知道的特殊属性?如果已经有一种很好的方法可以实现这一点,我宁愿不为此编写自己的包装器方法。如果您有一个字符串值,那么我能想到的最接近的方法就是使用Enum.TryParse
:
NetConnectionStatus result;
if (Enum.TryParse(stringValue, out result) == false)
result = NetConnectionStatus.Other;
对于要强制转换的整数值,可以使用:
result = (NetConnectionStatus)integerValue;
if (Enum.GetValues(typeof(NetConnectionStatus)).Contains(result) == false)
result = NetConnectionStatus.Other;
不太理想,但在C#中,枚举只不过是整数值的花哨名称,因此将枚举定义值之外的整数值填充到该枚举类型的值中是有效的
此解决方案将处理负数,或者比进行数字比较更优雅地处理枚举值中存在间隙的情况。这会很好,但不会。怎么样
var result = (NetConnectionStatus) 20;
Assert.IsTrue(result >= (int)NetConnectionStatus.Other);
NET没有“任何其他”枚举值存储桶。从技术上讲,枚举(enum)是一组基本类型的命名常量(以下类型之一:
sbyte
,short
,int
,long
及其无符号对应项)。您可以在没有任何损失的情况下向相应类型强制转换枚举值,如下例所示:
enum TestEnum:int // Explicitly stating a type.
{
OnlyElement=0
}
class Program
{
static void Main(string[] args)
{
// Console.WriteLine implicitly calls ToString of the TestEnum.OnlyElement.
Console.WriteLine("OnlyElement == {0}", TestEnum.OnlyElement);
//TestEnum.OnlyElement equals to 0, as demonstrated by this casting:
Console.WriteLine("(int)OnlyElement == {0}", (int)TestEnum.OnlyElement);
//We can do it in reverse...
Console.WriteLine("(TestEnum)0 == ",(TestEnum)0);
// But what happens when we try to cast a value, which is not
// representable by any of enum's named constants,
// into value of enum in question? No exception is thrown
// whatsoever: enum variable simply holds that value, and,
// having no named constant to associate it with, simply returns
// that value when attempting to "ToString"ify it:
Console.WriteLine("(TestEnum)5 == {0}", (TestEnum)5); //prints "(TestEnum)5 == 5".
Console.ReadKey();
}
}
我想再次重复一遍,.NET中的enum只是一个底层类型的值,带有一些漂亮的修饰,比如重写ToString方法和标志检查(如果您想了解更多关于标志的信息,请查看)。不能有一个只有14个值的整数,如“0..12和其他所有值”,因此不能有这样的枚举。在您的示例中,NetConnectionStatus.Other
只接收单个文本值(我假设它很可能是'13',作为基础类型的下一个可用正值-但是它实际上取决于编译器),就像任何其他枚举常量在未显式指定时所做的一样-而且,很明显,它不会变成桶
但是,有一些选项可以实现对整数/字节/短/长以及类似枚举的简单等式检查。考虑这种扩展方法:
static bool IsOther(this NetConnectionStatus A)
{
return (A < (NetConnectionStatus)0) || (A > (NetConnectionStatus)12);
}
及
(当然,您可以将IsOther
方法替换为isnother
,重载它,以及使用方法可以执行的几乎所有其他操作。)
现在还有一件事Enum
类本身包含一个名为IsDefined
的方法,该方法允许您避免检查特定Enum的值边界(12
),从而防止在添加/删除Enum值时出现不必要的错误,而取消绑定和检查Enum中的每个值是否匹配的性能代价很小(我不确定这是如何在引擎盖下工作的,我希望这些检查是优化的)。因此,您的方法如下所示:
var result = (NetConnectionStatus)10;
Trace.Assert(result.IsOther()); //No assertion is triggered; result is NetConnectionStatus.AuthenticationFailed
static bool IsOther(NetConnectionStatus A)
{
return !Enum.IsDefined(typeof(NetConnectionStatus), A);
}
int value = 13;
var result = value.ToEnum<NetConnectionStatus, int>();
Assert.AreEqual(NetConnectionStatus.Other, result);
(然而,从enum的名称来看,您似乎想制作一个网络应用程序/服务器,因为这些性能可能非常重要-但很可能我只是有点偏执,这不会成为您的应用程序的瓶颈。稳定性更值得关注,而且,除非您在性能方面遇到实际问题,它被认为是实现尽可能多的稳定性、安全性和可移植性的更好实践。Enum.IsDefined
比显式边界检查更易于理解、可移植和稳定。)
希望这能有所帮助!谢谢大家的回复。正如大家所确认的,确实没有现成的方法可以做到这一点。为了其他人的利益,我想我应该发布我最后编写的(自定义)代码。我编写了一个扩展方法,它利用了我称为
[CatchAll]
的枚举值上的自定义属性
public class CatchAll : Attribute { }
public static class EnumExtensions
{
public static T ToEnum<T, U>(this U value) where T : struct, IConvertible where U : struct, IComparable, IConvertible, IFormattable, IComparable<U>, IEquatable<U>
{
var result = (T)Enum.ToObject(typeof(T), value);
var values = Enum.GetValues(typeof(T)).Cast<T>().ToList();
if (!values.Contains(result))
{
foreach (var enumVal in from enumVal in values
let info = typeof(T).GetField(enumVal.ToString())
let attrs = info.GetCustomAttributes(typeof(CatchAll), false)
where attrs.Length == 1
select enumVal)
{
result = enumVal;
break;
}
}
return result;
}
}
这是:
ushort value = 20;
result = value.ToEnum<NetConnectionStatus, ushort>();
Assert.AreEqual(NetConnectionStatus.Other, result);
ushort值=20;
结果=value.ToEnum();
Assert.AreEqual(NetConnectionStatus.Other,result);
没有。net没有。你应该自己写一些东西。只是因为还没有人说过NetConnectionStatus.Other==13我认为这几乎是正确的。虽然它比>12
或>Other
检查更笨重,但它带有将所有其他值分配给Other
的意图,如果将项添加到枚举中,它不会改变,也不依赖Other
作为最后一个。我要做的一个更改正在使用if(Enum.IsDefined(typeof(MyEnum),value)
ushort value = 20;
result = value.ToEnum<NetConnectionStatus, ushort>();
Assert.AreEqual(NetConnectionStatus.Other, result);