C# 从整数强制转换时,如何定义“捕获所有”枚举值?

C# 从整数强制转换时,如何定义“捕获所有”枚举值?,c#,enums,C#,Enums,我的C#代码中定义了一个枚举类型,该枚举类型与Win32炣NetworkAdapter WMI表中NetConnectionStatus字段的所有可能值相对应,as 文档显示,从0到12的整数都有一个唯一的状态名称,但是13到65535之间的所有整数都集中到一个称为“其他”的存储桶中。因此,我的代码如下: [Serializable] public enum NetConnectionStatus { Disconnected = 0, Connecting = 1, C

我的C#代码中定义了一个枚举类型,该枚举类型与Win32炣NetworkAdapter WMI表中NetConnectionStatus字段的所有可能值相对应,as

文档显示,从0到12的整数都有一个唯一的状态名称,但是13到65535之间的所有整数都集中到一个称为“其他”的存储桶中。因此,我的代码如下:

[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);