也许在Visual Studio 2015年C#编译器的bug [英] Maybe a C# compiler bug in Visual Studio 2015

查看:296
本文介绍了也许在Visual Studio 2015年C#编译器的bug的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我觉得这是一个编译器错误。

I think this is a compiler bug.

下面的控制台应用程序编译UND完美执行时与2015年VS编译:

The following console application compiles und executes flawlessly when compiled with 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();
        }
    }
}

但现在它越来越怪异:这个code编译,但它抛出一个 TypeLoadException 时执行

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

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

你遇到同样的问题?如果是的话,我会在微软提交的问题。

Do you experience the same issue? If so, I will file an issue at Microsoft.

在code看起来毫无意义的,我却用它来提高可读性,并实现歧义。

The code looks senseless, but I use it to improve readability and to achieve disambiguation.

我有不同的重载类似

无效DoSomething的(MYSTRUCT?ARG1,ARG2串)

无效DoSomething的(字符串ARG1,ARG2字符串)

调用一个方法,这种方法...

Calling a method this way...

myInstance.DoSomething(NULL,世界,你好!)

...不能编译。

呼叫

myInstance.DoSomething(默认值(MYSTRUCT?),世界,你好!)

myInstance.DoSomething((MYSTRUCT?)空,世界,你好!)

工作,但长相丑陋。我preFER这种方式:

works, but looks ugly. I prefer it this way:

myInstance.DoSomething(MyStruct.Empty,世界,你好!)

如果我把空缺变到另一个阶级,一切工作好:

If I put the Empty variable into another class, everything works okay:

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

奇怪的行为,不是吗?

Strange behavior, isn't it?

这里我打开一票: http://github.com/dotnet/roslyn/issues/ 10126

一个新的机票已在这里隆重开幕: https://github.com/dotnet/coreclr/问题/ 4049

A new ticket has been opened here: https://github.com/dotnet/coreclr/issues/4049

推荐答案

这是不是在2015年的错误,但一个可能是C#语言错误。下面的讨论涉及到为什么的实例成员的不能引进循环,为什么一个可空< T> 将导致此错误,但不应适用于静成员。

This is not a bug in 2015 but a possibly a C# language bug. The discussion below relates to why instance members cannot introduce loops, and why a Nullable<T> will cause this error, but should not apply to static members.

我想提出它作为一个语言错误,而不是一个编译器错误。

I would submit it as a language bug, not a compiler bug.

在编制本VS2013 code给出以下编译错误:

Compiling this code in VS2013 gives the following compile error:

结构成员ConsoleApplication1.Program.MyStruct.Empty类型System.Nullable导致周期的结构布局

Struct member 'ConsoleApplication1.Program.MyStruct.Empty' of type 'System.Nullable' causes a cycle in the struct layout

一个快速搜索变成了其中规定这个答案

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

It's not legal to have a struct that contains itself as a member.

不幸的是, System.Nullable&LT; T&GT; 这是用于值类型的可空实例类型也是值类型,因此必须有一个固定的大小。人们很容易想到 MYSTRUCT?作为引用类型,但它确实是没有。 MYSTRUCT?的大小是根据 MYSTRUCT ...的规模,这显然介绍编译循环。

Unfortunately the System.Nullable<T> type which is used for nullable instances of value types is also a value type and must therefore have a fixed size. It's tempting to think of MyStruct? as a reference type, but it really isn't. The size of MyStruct? is based on the size of MyStruct... which apparently introduces a loop in the compiler.

就拿:

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?不是一个参考,但一个结构是4个字节(标准填充尺寸)长于 Struct1

Using System.Runtime.InteropServices.Marshal.SizeOf() you'll find that Struct2 is 16 bytes long, indicating that Struct1? is not a reference but a struct that is 4 bytes (standard padding size) longer than Struct1.

在回应朱利叶斯Depulla的回答和评论,这里是什么的真正的发生,当你访问一个静态可空&LT; T&GT; 字段。从这个code:

In response to Julius Depulla's answer and comments, here is what is actually happening when you access a static Nullable<T> field. From this code:

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

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

下面是LINQPad产生IL:

Here is the generated IL from LINQPad:

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 的地址,并推动它的堆栈。该地址的保证非空的如可空&LT;的Int32方式&gt; 是一个结构,而不是引用类型

The first instruction gets the address of the static field foo.Empty and pushes it on the stack. This address is guaranteed to be non-null as Nullable<Int32> is a structure and not a reference type.

下一步可空&LT;的Int32&GT; 隐藏的成员函数 get_HasValue 被调用来检索的HasValue 属性值。这会不会导致一个空引用,因为,如前所述previously,值类型字段的地址必须是非空,不管包含在该地址的值。

Next the Nullable<Int32> hidden member function get_HasValue is called to retrieve the HasValue property value. This cannot result in a null reference since, as mentioned previously, the address of a value type field must be non-null, regardless of the value contained at the address.

的其余部分的结果只是比较来0,并将结果发送到控制台。

The rest is just comparing the result to 0 and sending the result to the console.

在此过程中没有一点是有可能'调用的类型的空'是什么意思。值类型没有空地址,因此对价值类型的方法调用不能直接导致空对象引用错误。这就是为什么我们不叫他们引用类型。

At no point in this process is it possible to 'invoke a null on a type' whatever that means. Value types do not have null addresses, so method invocation on value types cannot directly result in a null object reference error. That's why we don't call them reference types.

这篇关于也许在Visual Studio 2015年C#编译器的bug的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆