记录个人一直以来对枚举定义和使用的两个误解_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 记录个人一直以来对枚举定义和使用的两个误解

记录个人一直以来对枚举定义和使用的两个误解

 2014/6/25 22:58:12  JeffWong  程序员俱乐部  我要评论(0)
  • 摘要:1、枚举定义声明基础类型的限制想要定义一个表示数据库主键编号范围的枚举:///<summary>///编号范围枚举///</summary>publicenumIDRangeType:Int64{///<summary>///1到2的32次方///</summary>[Description("1到2的32次方")]Between1ToPowerOf32=2147483748,///<summary>
  • 标签:使用 个人 误解 枚举

1、枚举定义声明基础类型的限制

想要定义一个表示数据库主键编号范围的枚举:

    /// <summary>
    /// 编号范围枚举
    /// </summary>
    public enum IDRangeType : Int64
    {
        /// <summary>
        /// 1到2的32次方
        /// </summary>
        [Description("1到2的32次方")]
        Between1ToPowerOf32 = 2147483748,

        /// <summary>
        /// 2的32次方到2的40次方
        /// </summary>
        [Description("2的32次方到2的40次方")]
        BetweenPowerOf32ToPowerOf40 = 2199023255552,

        /// <summary>
        /// 2的40次方以上
        /// </summary>
        [Description("2的40次方以上")]
        Bigger = Int64.MaxValue,

    }

但是上面这种声明直接导致编译错误应输入类型 byte、sbyte、short、ushort、int、uint、long 或 ulong 

也就是说,枚举的基础类型只能为8种数字类型: byte、sbyte、short、ushort、int、uint、long 或 ulong。声明为其他类型如Int16、Int32、Int64等都不行。

按照VS编译提示,将Int64改为long,果然通过,真是奇哉怪也。

我们平时理解的Int64和long其实在MS .Net Framework中是没有区别的,long只是Int64的一个别名而已(而Java的基元值类型的包装类都是引用类型),而且Framework编程规范里还明确说推荐使用Int64,这样可以保证跨语言或者跨平台代码移植方便。但是在枚举声明这里,只能使用别名。

顺带再提一下.NET Framework中非常特殊的一个类型System.Enum,它是个引用类型,Framework中将System.Enum定义为一个抽象类,但是它又继承自System.ValueType。

通过类型判断,却又发现它不是ValueType,而且也不是枚举:

            var num = new Int32();
            Console.WriteLine(num is ValueType); //True
            Console.WriteLine(num.GetType().IsValueType); //True

            var type = typeof(System.Enum);
            Console.WriteLine(type.IsValueType); //False ???
            Console.WriteLine(type.IsEnum); //False ???

C#语言特性中有很多特例存在,System.Enum即为一例。

 

2、web服务的客户端代理和服务端的枚举数值定义不一致

还以上面的枚举作为示例,我们要在一个标识为WebMethod的web服务方法中使用这个枚举,新建一个web服务并部署好以后供客户端调用。

通过WSDL工具,直接将这个web服务生成保存为本地代理类,然后查看代理类源代码,客户端代理类生成的枚举IDRangeType竟然变成:

    public enum IDRangeType : long
    {

        Between1ToPowerOf32,


        BetweenPowerOf32ToPowerOf40,


        Bigger,

    }

客户端生成的枚举,没有把服务端枚举定义中显式定义的数值带过来。对于IDRangeType这种定义枚举就是要使用枚举的数值而言,简直太出乎人的意料之外。

然后想到可能是序列化和反序列化的问题,尝试着给枚举属性分别加上特性DataMember和EnumMember,问题依旧。但在WCF试验中发现一切正常,打开WCF生成的客户端代理类,枚举数值的定义和服务端没什么变化。

后来想想又搞不明白,枚举既然是继承自基元值类型,那么值类型怎么序列化,枚举也应该像基元值类型一样序列化才对,而且一直说服务分享 Schema(for structures) 和 Contract(for behaviors), 而不是 Class,难道枚举不是Schema和Contract的一部分,或者是SOAP的.NET实现不支持枚举?

试验多次久久不能解决问题,最后搜索一下.net web服务和枚举这两个关键字,发现果然很早就有一篇流传甚广的Web Services and C# Enums文章讲到“Numeric Values Are Not Preserved”这个事情。文章还有提到,在web服务中,Flag标记下的枚举在客户端生成的时候数值改变,很容易导致灾难后果(This can lead to disastrous consequences)。

通过这个问题,让我深深意识到服务端和客户端生成代码的差异,不同环境不同应用场景下,有些特殊情况很容易偏离习惯认知和主观判断,必须多尝试实践才能出真知。

 

参考:

http://ikriv.com/dev/dotnet/webservices_and_enums.html

http://msdn.microsoft.com/zh-cn/library/System.Web.Services(v=vs.110).aspx

http://msdn.microsoft.com/zh-cn/library/sbbt4032.aspx

http://msdn.microsoft.com/zh-cn/library/aa347875(v=vs.110).aspx

上一篇: 富士康在美国起诉东芝等3家日本公司侵权 下一篇: 没有下一篇了!
发表评论
用户名: 匿名