zoukankan      html  css  js  c++  java
  • 记录个人一直以来对枚举定义和使用的两个误解

    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

  • 相关阅读:
    python入门1
    查找字段 和查找组件
    DBGRID 拖动滚动条 和 鼠标滚轮的问题
    数据集 过滤时 RecordCount 属性
    查找字段 如何 过滤
    数据集控件 放在 数据模块 上后,如何写事件代码
    取TTable 过滤后的记录数
    判断 Windows操作系统是32位还是64位
    MatchText MatchStr 区别
    EClassNotFound
  • 原文地址:https://www.cnblogs.com/jeffwongishandsome/p/two-misunderstanding-about-enum.html
Copyright © 2011-2022 走看看