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

2024-01-01

由于我不知道究竟是哪一部分触发了错误,所以我不完全确定如何更好地标记它。

这个问题是SO问题的副产品C# 代码似乎以无效的方式进行优化,导致对象值变为 null https://stackoverflow.com/questions/3379894/c-code-seems-to-get-optimized-in-an-invalid-way-such-that-an-object-value-become,我试图帮助Gary https://stackoverflow.com/users/301903/gary与昨天晚上。他是那个发现存在问题的人,我刚刚将问题简化为一个更简单的项目,并希望在进一步处理之前进行验证,因此这里有这个问题。

如果其他人可以验证他们也遇到这个问题,我会在 Microsoft Connect 上发布一条说明,当然我希望 Jon、Mads 或 Eric 也能看看它:)

它涉及:

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

代码可以在这里找到:代码库 http://hg.vkarlsen.no/hgweb.cgi/StackOverflow/file/tip/SO3379894.

如果您想亲自动手,我将在下面发布有关如何制作项目的描述。

该问题的表现是,在返回一个简单的通用列表之前,在方法调用中产生无效的转换,在返回之前将其转换为奇怪的东西。原始代码最终转换为布尔值,是的,布尔值。编译器添加了来自 a 的强制转换List<SomeEntityObject>在返回结果之前转换为布尔值,并且方法签名表示它将返回一个List<SomeEntityObject>。这反过来会导致运行时出现奇怪的问题,方法调用的结果中的所有内容都被视为“优化掉”(原始问题),或者崩溃BadImageFormatException or InvalidProgramException或类似的例外之一。

在我复制这个的过程中,我看到了一个演员void[],我的代码的当前版本现在转换为TypedReference。在一种情况下,Reflector 崩溃了,因此在这种情况下代码很可能无法实现。您的里程可能会有所不同。

以下是重现它的方法:

Note:可能有更多的最小形式可以重现该问题,但将所有代码移至一个项目即可使其消失。从类中删除泛型也会使问题消失。下面的代码每次都会为我重现该问题,因此我将其保留原样。

我对下面代码中转义的 html 字符表示歉意,这是 Markdown 在捉弄我,如果有人知道我如何纠正它,请告诉我,或者只是编辑问题

  1. 为 .NET 4.0 创建一个包含控制台应用程序的新 Visual Studio 2010 解决方案
  2. 添加两个新项目,都是类库,也是 .NET 4.0(我假设它们被命名为 ClassLibrary1 和 ClassLibrary2)
  3. 调整所有项目以使用完整的 .NET 4.0 运行时,而不仅仅是客户端配置文件
  4. 在控制台项目中添加对 ClassLibrary2 的引用
  5. 将类库 2 中的引用添加到类库 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;
            }
        }
    }
    
  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>();
            }
        }
    }
    
  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();
            }
        }
    }
    
  11. 构建并确保没有编译器错误

  12. 现在尝试运行该程序。这应该会因更可怕​​的异常之一而崩溃。我见过 InvalidProgramException 和 BadImageFormatException,具体取决于演员最终的结果
  13. 查看Reflector中Dummy.GetDummies的生成代码。源代码如下所示:

    public List<Dummy> GetDummies()
    {
        var policy = Cache.GetDefaultCacheItemPolicy();
        return new List<Dummy>();
    }
    

    然而 Reflector 说(对我来说,它为你选择的演员可能会有所不同,在一种情况下 Reflector 甚至崩溃了):

    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;
    }
    

现在,除了上面的崩溃/无效代码之外,还有一些奇怪的事情:

  • 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上面有“尝试注释掉”注释,您会得到相同的编译器错误


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

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

可能是C# 4.0编译器错误,其他人可以验证吗? 的相关文章

随机推荐