可能的C#4.0编译错误,其他人可以验证吗?

ang*_*son 10 compiler-bug c#-4.0

由于我不确切地知道触发错误的确切部分,我不完全确定如何更好地标记它.

这个问题是SO问题的副产品c#代码似乎以无效方式优化,使得对象值变为null,我试图在昨天晚上帮助Gary.他是那个发现存在问题的人,我只是将问题简化为一个更简单的项目,并且在我进一步研究之前需要验证,因此这里有这个问题.

如果其他人可以验证他们是否也遇到了这个问题,我会发布一条关于Microsoft Connect的说明,当然我希望Jon,Mads或Eric也会看一下它:)

它涉及:

  • 3个项目,其中2个是类库,其中一个是控制台程序(最后一个不需要重现问题,但只是执行它显示问题,而你需要使用反射器并查看编译的代码如果你不添加它)
  • 不完整的引用和类型推断
  • 泛型

代码可在此处获得:代码库.

如果您想亲自动手,我会在下面发布如何制作项目的说明.

该问题通过在方法调用中生成无效的强制转换,在返回一个简单的泛型列表,在返回之前将其转换为奇怪的东西来展示自身.最初的代码最后是一个强制转换为布尔值,是的,一个布尔值.List<SomeEntityObject>在返回结果之前,编译器从a添加了一个强制转换,并且方法签名表示它将返回一个List<SomeEntityObject>.这反过来又导致在运行时奇怪的问题,一切从方法调用的结果被认为是"优化掉"(原题),或一方崩溃BadImageFormatException或者InvalidProgramException或类似的例外之一.

在我重现这个的过程中,我看到了一个void[]强制转换器,我的代码的当前版本现在被转换为TypedReference.在一个案例中,Reflector崩溃,因此在这种情况下,代码很可能超出了希望.您的里程可能有所不同

以下是重现它的方法:

注意:可能有更多的最小形式可以重现问题,但将所有代码移动到一个项目使其消失.从类中删除泛型也会使问题消失.下面的代码每次都为我重现问题,所以我将它保留原样.

我为下面代码中的转义html字符道歉,这是Markdown对我玩耍的技巧,如果有人知道如何纠正它,请让我知道,或者只是编辑问题

  1. 为.NET 4.0创建包含控制台应用程序的新Visual Studio 2010解决方案
  2. 添加两个新项目,包括类库,还有.NET 4.0(我将假设它们被命名为ClassLibrary1和ClassLibrary2)
  3. 调整所有项目以使用完整的.NET 4.0运行时,而不仅仅是客户端配置文件
  4. 将控制台项目中的引用添加到ClassLibrary2
  5. 将ClassLibrary2中的引用添加到ClassLibrary 1
  6. 删除默认添加到类库的两个Class1.cs文件
  7. 在ClassLibrary1中,添加对System.Runtime.Caching的引用
  8. 将新文件添加到ClassLibrary1,将其命名为DummyCache.cs,并粘贴以下代码:

    using System;
    using System.Collections.Generic;
    using System.Runtime.Caching;
    
    namespace ClassLibrary1
    {
        public class DummyCache<TModel> where TModel : new()
        {
            public void TriggerMethod<T>()
            {
            }
            // Try commenting this out, note that it is never called!
            public void TriggerMethod<T>(T value, CacheItemPolicy policy)
            {
            }
            public CacheItemPolicy GetDefaultCacheItemPolicy()
            {
                return null;
            }
            public CacheItemPolicy GetDefaultCacheItemPolicy(IEnumerable<string> dependentKeys, bool createInsertDependency = false)
            {
                return null;
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  9. 将新文件添加到ClassLibrary2,将其命名为Dummy.cs并粘贴以下代码:

    using System;
    using System.Collections.Generic;
    using ClassLibrary1;
    
    namespace ClassLibrary2
    {
        public class Dummy
        {
            private DummyCache<Dummy> Cache { get; set; }
            public void TryCommentingMeOut()
            {
                Cache.TriggerMethod<Dummy>();
            }
            public List<Dummy> GetDummies()
            {
                var policy = Cache.GetDefaultCacheItemPolicy();
                return new List<Dummy>();
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  10. 粘贴到控制台项目的Program.cs中的以下代码中:

    using System;
    using System.Collections.Generic;
    using ClassLibrary2;
    
    namespace ConsoleApplication23
    {
        class Program
        {
            static void Main(string[] args)
            {
                Dummy dummy = new Dummy();
                // This will crash with InvalidProgramException
                // or BadImageFormatException, or a similar exception
                List<Dummy> dummies = dummy.GetDummies();
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  11. 构建,并确保没有编译器错误

  12. 现在尝试运行该程序.这应该是一个更可怕的例外.我已经看到了InvalidProgramException和BadImageFormatException,具体取决于演员最终的结果
  13. 查看Reflector中生成的Dummy.GetDummies代码.源代码如下所示:

    public List<Dummy> GetDummies()
    {
        var policy = Cache.GetDefaultCacheItemPolicy();
        return new List<Dummy>();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    反射器说(对我来说,它可能会因为它为你选择的投射而有所不同,并且在一种情况下反射器甚至崩溃):

    public List<Dummy> GetDummies()
    {
        List<Dummy> policy = (List<Dummy>)this.Cache.GetDefaultCacheItemPolicy();
        TypedReference CS$1$0000 = (TypedReference) new List<Dummy>();
        return (List<Dummy>) CS$1$0000;
    }
    
    Run Code Online (Sandbox Code Playgroud)

现在,这里有几个奇怪的事情,上面的崩溃/无效代码:

  • Library2 Dummy.GetDummies执行调用以从Library1获取类的默认缓存策略.它使用类型推断var policy = ...,结果是一个CacheItemPolicy对象(代码中为null,但类型很重要).

    但是,ClassLibrary2没有对System.Runtime.Caching的引用,因此不应该编译.

    事实上,如果你在Dummy中注释掉名为的方法TryCommentingMeOut,你会得到:

    "System.Runtime.Caching.CacheItemPolicy"类型在未引用的程序集中定义.您必须添加对程序集'System.Runtime.Caching,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a'的引用.

    为什么让这个方法存在让编译器开心我不知道,我甚至不知道这是否与当前问题有关.也许这是第二个错误.

  • 有一个类似的方法DummyCache,如果你恢复方法Dummy,以便代码再次编译,然后注释掉该方法,DummyCache其上面有"试着评论出来"注释,你得到相同的编译器错误

Hen*_*man 2

好的,我下载了您的代码,可以按照描述确认问题。

我没有对此进行任何广泛的修改,但是当我运行&反射器发布构建时,一切似乎都正常(= null ref 异常和干净的反汇编)。
Reflector (6.10.11) 在调试版本中崩溃。

还有一个实验:我想知道 CacheItemPolicies 的使用,因此我将其替换为我自己的 MyCacheItemPolicy(在第三类库中),并且弹出了相同的 BadImageFormat 异常。

异常提到:{“错误的二进制签名。(来自 HRESULT 的异常:0x80131192)”}