c# - 可能是Visual Studio 2015中的C#编译器错误

标签 c# visual-studio-2015 roslyn compiler-bug coreclr

我认为这是一个编译器错误。

当使用VS 2015进行编译时,以下控制台应用程序可以编译并完美执行:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = MyStruct.Empty;
        }

        public struct MyStruct
        {
            public static readonly MyStruct Empty = new MyStruct();
        }
    }
}


但是现在变得很奇怪:此代码可以编译,但是在执行时会抛出TypeLoadException

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = MyStruct.Empty;
        }

        public struct MyStruct
        {
            public static readonly MyStruct? Empty = null;
        }
    }
}


您是否遇到相同的问题?如果是这样,我将向Microsoft提出问题。

该代码看起来毫无意义,但是我使用它来提高可读性并消除歧义。

我有不同的重载方法,如

void DoSomething(MyStruct? arg1, string arg2)

void DoSomething(string arg1, string arg2)

以这种方式调用方法...

myInstance.DoSomething(null, "Hello world!")

...无法编译。

呼唤

myInstance.DoSomething(default(MyStruct?), "Hello world!")

要么

myInstance.DoSomething((MyStruct?)null, "Hello world!")

可以,但是看起来很丑。我更喜欢这样:

myInstance.DoSomething(MyStruct.Empty, "Hello world!")

如果将Empty变量放入另一个类,则一切正常:

public static class MyUtility
{
    public static readonly MyStruct? Empty = null;
}


奇怪的行为,不是吗?



更新2016-03-29

我在这里开了票:http://github.com/dotnet/roslyn/issues/10126



更新2016-04-06

新的票证已在此处打开:https://github.com/dotnet/coreclr/issues/4049

最佳答案

这不是2015年的错误,但可能是C#语言错误。下面的讨论涉及为什么实例成员不能引入循环,以及为什么Nullable<T>会导致此错误,但不适用于静态成员。

我将其提交为语言错误,而不是编译器错误。



在VS2013中编译此代码会产生以下编译错误:


  类型为“ System.Nullable”的结构成员“ ConsoleApplication1.Program.MyStruct.Empty”导致结构布局中的循环


快速搜索出现this answer,其中指出:


  具有包含自身作为成员的结构是不合法的。


不幸的是,用于值类型的可为空的实例的System.Nullable<T>类型也是一个值类型,因此必须具有固定的大小。将MyStruct?视为引用类型很诱人,但实际上并非如此。 MyStruct?的大小基于MyStruct的大小...显然在编译器中引入了循环。

例如:

public struct Struct1
{
    public int a;
    public int b;
    public int c;
}

public struct Struct2
{
    public Struct1? s;
}


使用System.Runtime.InteropServices.Marshal.SizeOf(),您会发现Struct2长16个字节,表明Struct1?不是引用,而是比Struct1长4个字节(标准填充大小)的结构。



这里没有发生什么

为了响应朱利叶斯·德普拉(Julius Depulla)的回答和评论,这是您访问static Nullable<T>字段时实际发生的情况。从此代码:

public struct foo
{
    public static int? Empty = null;
}

public void Main()
{
    Console.WriteLine(foo.Empty == null);
}


这是从LINQPad生成的IL:

IL_0000:  ldsflda     UserQuery+foo.Empty
IL_0005:  call        System.Nullable<System.Int32>.get_HasValue
IL_000A:  ldc.i4.0    
IL_000B:  ceq         
IL_000D:  call        System.Console.WriteLine
IL_0012:  ret         


第一条指令获取静态字段foo.Empty的地址,并将其压入堆栈。由于Nullable<Int32>是结构而不是引用类型,因此保证该地址为非空。

接下来,调用Nullable<Int32>隐藏成员函数get_HasValue来检索HasValue属性值。如前所述,这不能导致空引用,因为值类型字段的地址必须为非空值,而与该地址中包含的值无关。

剩下的只是将结果与0进行比较并将结果发送到控制台。

在此过程中,无论如何都不可能“在类型上调用null”。值类型没有空地址,因此对值类型的方法调用不能直接导致空对象引用错误。这就是为什么我们不称它们为引用类型的原因。

关于c# - 可能是Visual Studio 2015中的C#编译器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42317904/

相关文章:

c# - Hook 到 Roslyn 构建过程

c# - 在 Cake 中使用语句

c# - wpf C# 检索强调色窗口 10

c# - 用于将图像添加到图像管理器的 Enterprise Architect API

c++ - 终止时的异常处理

android - 如何减少 Visual Studio 2015 中 Xamarin Forms 应用程序的用户代码大小?

xaml - Visual Studio 2015 XAML 编辑器文本颜色

c# - 只能通过单击使用的按钮。没有进入,没有返回。只需点击一下

c# - 人们在使用 TVP 将 DataTable/Collection 发送到 SQL Server 时遇到了什么问题

c# - 无法删除\bin\roslyn\VBCSCompiler.exe - 访问被拒绝