雁过请留痕...
代码改变世界

枚举Enum和常量0之间的恩怨

2013-11-29 15:13  xiashengwang  阅读(2689)  评论(0编辑  收藏  举报

1,任何为0的常量表达式都能隐式的转换成枚举Enum。

对于这一点,在程序中没少吃苦头。特别是对于函数重载的情况,往往让人一头雾水。

看看下面的代码(摘自MSDN),你能猜到输出吗?

public enum E
{
    Zero = 0,
    One = 1,
} 

class A
{
    public A(string s, object o)
    { System.Console.WriteLine("{0} => A(object)", s); } 

    public A(string s, E e)
    { System.Console.WriteLine("{0} => A(Enum E)", s); }
} 

class B
{
    static void Main()
    {
        A a1 = new A("0", 0);
        A a2 = new A("1", 1);
        A a3 = new A("(int) E.Zero", (int) E.Zero);
        A a4 = new A("(int) E.One", (int) E.One);
    }
}
Visual C# 2005 output:
0 => A(Enum E)
1 => A(object)
(int) E.Zero => A(object)
(int) E.One => A(object)

Visual C# 2008 output:
0 => A(Enum E)
1 => A(object)
(int) E.Zero => A(Enum E)
(int) E.One => A(object)

自VS2008起,所有能确定为0的常量表达式都能隐式的转换成Enum。

所以如果不想要这种隐式的转换的话,在程序中处理0时,就需要转换。

再来看看我的测试例子:

namespace WZTEST
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public void SqlParameter(string parameterName, object value)
        {
            //object
        }

        public void SqlParameter(string parameterName, SqlDbTypeA dbType)
        {
            //Enum
        }

        private void button1_Click(object sender, EventArgs e)
        {
            const int ZERO = 0;
            SqlParameter("aa", 0);
            SqlParameter("aa", (int)0);
            SqlParameter("aa", ZERO);
            SqlParameter("aa", Convert.ToInt32(0));
        }
    }

    public enum SqlDbTypeA
    {
        Int = 1
    }
}

我们来反编译下button1_Click函数,看看编译器都做了什么。

private void button1_Click(object sender, EventArgs e)
{
    this.SqlParameter("aa", (SqlDbTypeA) 0);
    this.SqlParameter("aa", (SqlDbTypeA) 0);
    this.SqlParameter("aa", (SqlDbTypeA) 0);
    this.SqlParameter("aa", Convert.ToInt32(0));
}

傻眼了吧!前面三个全部变成了Enum。好吧,既然斗不过微软,那就只有接受这个结果。

结论:对于有Enum的重载函数,传入0时,最好用Convert转换;或者用一个变量赋值0后再传入函数,以避开万恶的编译器规则。

备注:微软这样做的原因是Enum和0之间的比较比较频繁,为了方便开发者,就做了这样的隐式转换;但却给函数重载留下隐患,稍不小心就会犯错。