简体   繁体   English

为什么 Visual Studio 将新创建的数组键入为 Nullable?

[英]Why does Visual Studio Type a Newly Minted Array as Nullable?

I'm writing a function with a generic type TVal .我正在编写一个具有通用类型 TVal 的TVal I wrote this line:我写了这一行:

var zeroBased = new TVal[size];

And then in Visual Studio (VS) I used alt+enter to replace var with an explicit type.然后在 Visual Studio (VS) 中,我使用 alt+enter 将var替换为显式类型。 Here's what I got:这是我得到的:

TVal[]? zeroBased = new TVal[size];

I was surprised to find the ?我惊讶地发现? operator, indicating that the type might be nullable.运算符,指示该类型可能为空。 I thought that I'd be safe enough assuming the type is never null when created with new , and could have just done:我认为在使用new创建时,假设类型永远不会是 null ,我会足够安全,并且可以这样做:

TVal[] zeroBased = new TVal[size];

Is there a scenario where instantiating a new array in C# can give you back null?是否存在在 C# 中实例化一个新数组的情况可以让您返回 null?

Note: the code seems to compile fine without the ?注意:代码似乎没有? , I'm just intrigued by VS's suggestion... ,我只是对VS的建议很感兴趣......

Minimal Verifiable Example最小可验证示例

Open Visual Studio, same version as specified below, create a new project, enable nullable types as per the VS Project File Contents below, create a new class, and pop in this function:打开Visual Studio,与下面指定的相同版本,创建一个新项目,根据下面的VS项目文件内容启用可空类型,创建一个新的class,然后弹出这个function:

public void Test<T>(int size)
{
  var tArr = new T[size];
}

The select the var and hit alt+enter , and choose to replace var with explicit type. select var并点击alt+enter ,并选择将var替换为显式类型。 If the behaviour is the same as the one I experienced, you'll get:如果行为与我所经历的相同,您将得到:

public void Test<T>(int size)
{
  T[]? tArr = new T[size];
}

Visual Studio Project File Contents Visual Studio 项目文件内容

We're using C# 8 for this project and we've enabled Nullables:我们在这个项目中使用 C# 8 并且我们启用了 Nullables:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <Nullable>enable</Nullable>
    <LangVersion>8.0</LangVersion>
    <WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors>
    <TargetFramework>netstandard2.0</TargetFramework>
    <OutputType>Library</OutputType>
    <Version>1.0.0.9</Version>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
    <PackageReference Include="System.Dynamic.Runtime" Version="4.3.0" />
  </ItemGroup>

</Project>

Visual Studio Version Info (just bits that seemed important to this Q) Visual Studio 版本信息(只是对这个 Q 来说很重要的部分)

Microsoft Visual Studio Community 2019 Version 16.6.1 VisualStudio.16.Release/16.6.1+30128.74 Microsoft .NET Framework Version 4.7.03062 Microsoft Visual Studio Community 2019 版本 16.6.1 VisualStudio.16.Release/16.6.1+30128.74 Microsoft .NET 框架版本 4.7.03062

Installed Version: Community安装版本:社区

C# Tools 3.6.0-4.20251.5+910223b64f108fcf039012e0849befb46ace6e66 C# components used in the IDE. C# Tools 3.6.0-4.20251.5+910223b64f108fcf039012e0849befb46ace6e66 C# components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.根据您的项目类型和设置,可能会使用不同版本的编译器。

I would like to extend an existing answer by adding some links我想通过添加一些链接来扩展现有答案

C# specification proposal says : C# 规范提案说

nullable implicitly typed local variables可为空的隐式类型局部变量

var infers an annotated type for reference types. var推断引用类型的注释类型。 For instance, in var s = "" ;例如,在var s = "" ; the var is inferred as string? var被推断为string? . .

It means that var for reference types infers a nullable reference type.这意味着引用类型的var推断出可为空的引用类型。 This works if nullable context is enabled either using project file or #nullable pragma.如果使用项目文件或#nullable pragma 启用了可为nullable context ,则此方法有效。

This behavior was discussed in this LDM and implemented in this issue .此行为已在此 LDM中讨论并在此问题中实施。

This is a reason for making var infer a nullable reference type: 这是使var infer 为可空引用类型的原因:

At this point we've seen a large amount of code that requires people spell out the type instead of using var, because code may assign null later.此时我们已经看到大量代码需要人们拼出类型而不是使用 var,因为代码可能稍后会分配 null。

I would like to extend existing answers with my own interpretation.我想用我自己的解释来扩展现有的答案。 MikeJ's answer cracked this problem and got to the heart of it. MikeJ 的回答解决了这个问题并触及了它的核心。 It all boils down to nullability being enabled- which we had for this project (but not others, which is what threw me off.).这一切都归结为启用了可空性——我们为这个项目启用了这一点(但不是其他项目,这让我很失望。)。

Iliar Turdushev's answer then added some explicit references in support of the original answer. Iliar Turdushev 的回答随后添加了一些明确的引用来支持原始答案。 In particular, we were pointed to a recent discussion by the C# team on Github .特别是,我们注意到 C# 团队最近在 Github 上的讨论 That document, and the existing answer, quoted it saying the following:该文件和现有的答案引用它说如下:

At this point we've seen a large amount of code that requires people spell out the type instead of using var, because code may assign null later.此时我们已经看到大量代码需要人们拼出类型而不是使用 var,因为代码可能稍后会分配 null。

I found this difficult to understand without the context.如果没有上下文,我发现这很难理解。 So here is the context that explains the above:所以这里是解释上述内容的上下文:

var current = myLinkedList.Head; // annotated not null
while (current is object)
{
    ...
    current = current.Next; // warning, Next is annotated nullable, but current is non-null
}

Breaking it down, let's look at that first line:分解它,让我们看一下第一行:

var current = myLinkedList.Head; // annotated not null

Since the Head property is annotated as not null, it would be perfectly OK for the compiler to interpret the var as non-nullable.由于Head属性被注释为 not null,编译器将 var 解释为不可为空是完全可以的。 However, this non-nullability would then stick with the variable forever, even if, at some point in the program, we wanted to make it null eg in this line:但是,这种不可为空性将永远与变量保持一致,即使在程序中的某个时刻,我们希望将其设为 null,例如在这一行中:

 current = current.Next; // warning, Next is annotated nullable, but current is non-null

The C# team said, OK, we have two options here. C# 团队说,好的,我们这里有两个选择。 We can either interpret var as nullable always, or we can interpret it as non-nullable when it's inferrible from context, and allow users to specify var?我们可以将var解释为始终可以为空,或者我们可以在从上下文中推断出它时将其解释为不可为空,并允许用户指定var? to explicitly state that they want a nullable type.明确 state 他们想要一个可为空的类型。 But my reading of their document is that var?但我对他们文件的阅读是那个var? sort of violates the whole principle of var , which is convenience.有点违反var的整个原则,即方便。 If we had to stick an extra ?如果我们不得不坚持一个额外的? onto the end of var every time we used it, it's probably time we just got explicit about the type and stopped using var.每次我们使用var时,它可能是我们明确类型并停止使用 var 的时候了。

Thus, the C# team conclude:因此,C# 团队得出结论:

Make var have a nullable annotated type and infer the flow type as normal.使 var 具有可为空的注释类型并正常推断流类型。

This means that if you assign a non-nullable to a var , you can safely assign null to that same reference later on in the code without getting any warnings.这意味着,如果您将不可为空的值分配给var ,您可以安全地将 null 分配给稍后在代码中的相同引用,而不会收到任何警告。 Hans commented about this too. 汉斯也对此发表了评论。 So, for example, bringing it back to the original Q, I could do:所以,例如,把它带回原来的 Q,我可以这样做:

public void Test<T>(int size)
{
  var tArr = new T[size];
  //Some code
  tArr = null; //This is OK, because var is treated as T[]?, not T[]
}

And I wouldn't get any warnings.而且我不会收到任何警告。 So VS is behaving properly here- it's respecting the behaviour of the compiler to treat a var as nullable, as designed, even when that var is initialised to a non-nullable value .所以 VS 在这里表现得很好——它尊重编译器的行为,将var视为可空的,按照设计,即使该 var 被初始化为不可为空的值 Meaning, and this is the key point for me and the heart of my question:意思是,这对我来说是关键点,也是我问题的核心:

It's up to you as the programmer to remove nullability after converting a var to an explicit type, if that's what you want.作为程序员,您可以在将 var 转换为显式类型后删除可空性,如果这是您想要的。

And that's just what I will do in this case!这就是我在这种情况下要做的!

Visual Studio with C# 8 allows you to use nullable types according to the contexts you setup in your project.带有 C# 8 的 Visual Studio 允许您根据您在项目中设置的上下文使用可为空的类型。 You can find docs Here .您可以在此处找到文档。

One way to enable it is with a <Nullable>enable</Nullable> entry in your project file.启用它的一种方法是在项目文件中使用<Nullable>enable</Nullable>条目。 If you have that then it'll choose to use the nullable type when you convert to explicit variable.如果您有,那么当您转换为显式变量时,它将选择使用可空类型。

I'm not sure if that same behavior would be used for the other ways - pragmas for example - to enable it.我不确定是否将相同的行为用于其他方式(例如编译指示)来启用它。 I only tried the project file method.我只尝试了项目文件方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Visual Studio 2012无法识别可空类型 - Visual Studio 2012 not recognising nullable type Visual Studio 无法识别新添加的 class - Visual studio does not recognize newly added class 为什么Visual Studio会给我这种预期的错误类型 - Why does visual studio give me this error type expected 为什么在可为空的类型上使用+ =会导致FORWARD_NULL缺陷 - Why does using += on a nullable type result in a FORWARD_NULL defect 为什么这会产生一个可为空的数组/如何创建不可为空的数组 - Why does this produce a nullable array / How to create non-nullable array 为什么当值类型可以为空时,ApiController 返回空字典? - Why does ApiController return empty Dictionary when the value type is nullable? WPF绑定,C#泛型和可为空的类型导致Visual Studio Designer中出现未处理的异常 - WPF binding, C# Generics and nullable type result in Unhandled Exception in Visual Studio Designer 为什么Visual Studio代码样式设置认为DateTime不是内置类型但Guid就像它一样? - Why does Visual Studio code style settings think DateTime is not a built-in type but Guid acts like it is? 为什么此代码会使Visual Studio 2015崩溃? - Why does this code crash Visual Studio 2015? 为什么Visual Studio在调试时停止? - Why does Visual Studio stall while debugging?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM