代码之家  ›  专栏  ›  技术社区  ›  SLaks

(this==null)在C#中!

  •  127
  • SLaks  · 技术社区  · 15 年前

    由于在C#4中修复了一个bug,下面的程序将打印 true . (在LINQPad中尝试)

    void Main() { new Derived(); }
    
    class Base {
        public Base(Func<string> valueMaker) { Console.WriteLine(valueMaker()); }
    }
    class Derived : Base {
        string CheckNull() { return "Am I null? " + (this == null); }
        public Derived() : base(() => CheckNull()) { }
    }
    

    在VS2008的发布模式中,它抛出InvalidProgrameException。(在调试模式下,它工作正常)

    在VS2010 Beta 2中,它没有编译(我没有尝试Beta 1);我通过艰苦的方式学会了这一点

    还有别的办法吗 this == null 用纯C#?

    6 回复  |  直到 11 年前
        1
  •  73
  •   Mehrdad Afshari    7 年前

    此观察结果已发布在年的StackOverflow上 another question 今天早些时候。

    Marc great answer to that question 表示根据规范(第7.5.7节),您不能访问 this 在这种情况下,在C#3.0编译器中这样做的能力是一个bug。根据规范,C#4.0编译器运行正常(即使在Beta 1中,这也是编译时错误):

    A. 这个通道 由保留字组成 .

    此访问:

    this
    

        2
  •  24
  •   SLaks    15 年前

    调试模式二进制文件的原始反编译(没有优化的反射器)是:

    private class Derived : Program.Base
    {
        // Methods
        public Derived()
        {
            base..ctor(new Func<string>(Program.Derived.<.ctor>b__0));
            return;
        }
    
        [CompilerGenerated]
        private static string <.ctor>b__0()
        {
            string CS$1$0000;
            CS$1$0000 = CS$1$0000.CheckNull();
        Label_0009:
            return CS$1$0000;
        }
    
        private string CheckNull()
        {
            string CS$1$0000;
            CS$1$0000 = "Am I null? " + ((bool) (this == null));
        Label_0017:
            return CS$1$0000;
        }
    }
    

    编译器生成的方法没有意义;如果您查看IL(如下所示),它正在对null调用该方法 一串 (!).

       .locals init (
            [0] string CS$1$0000)
        L_0000: ldloc.0 
        L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
        L_0006: stloc.0 
        L_0007: br.s L_0009
        L_0009: ldloc.0 
        L_000a: ret 
    

    在释放模式下,局部变量被优化掉,因此它尝试将不存在的变量推送到堆栈上。

        L_0000: ldloc.0 
        L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
        L_0006: ret 
    

    (将其转换为C#时,反射镜会崩溃)


    编辑 ldloc ?

        3
  •  11
  •   Community Egal    7 年前

    alt text

        4
  •  10
  •   user1228 user1228    15 年前

    这不是一个“错误”。这是你滥用打字系统。您永远不应该传递对当前实例的引用( this )构造函数中的任何人。

    我也可以通过在基类构造函数中调用虚拟方法来创建类似的“bug”。

    可以 做坏事并不意味着这是一个错误

        5
  •  3
  •   Dan Tao    15 年前

    我可能错了,但我很确定你的目标是 null 永远不会有这样的情况 this 应用。

    例如,你会怎么打电话 CheckNull

    Derived derived = null;
    Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException
    
        6
  •  -1
  •   Scott and the Dev Team    14 年前

        public static T CheckForNull<T>(object primary, T Default)
        {
            try
            {
                if (primary != null && !(primary is DBNull))
                    return (T)Convert.ChangeType(primary, typeof(T));
                else if (Default.GetType() == typeof(T))
                    return Default;
            }
            catch (Exception e)
            {
                throw new Exception("C:CFN.1 - " + e.Message + "Unexpected object type of " + primary.GetType().ToString() + " instead of " + typeof(T).ToString());
            }
            return default(T);
        }
    

    示例:UserID=CheckForNull(Request.QueryString[“UserID”],147);

    推荐文章