在VS2019中测试C# 9.0 - CS0518 IsExternalInit未定义或未导入...如何定义/导入它?

72

编辑 [2020年11月29日]: .NET 5.0已经发布,但如果您的目标是.NET Standard 2.1,则仍需要下面的解决方案。


C# 9.0仍在开发中。有几个参考资料让我相信现在应该可以测试一些功能。

  1. 由Mr. Awesome本人撰写的微软博客,介绍了这些功能。https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/
  2. Github上的语言跟踪页面:https://github.com/dotnet/roslyn/blob/master/docs/Language%20Feature%20Status.md

我正在使用VS 2019 16.7预览版3.1。我已将语言版本选择为预览版,以供项目使用。

我可以使用一些C# 9特性。例如:Dictionary<string, object> Stuff = new()

但是使用新的init特性会导致此错误:Error CS0518 预定义类型“System.Runtime.CompilerServices.IsExternalInit”未定义或未导入

我该如何解决这个问题?

导致错误的代码示例:

class Test
{
   public int Hello { get; init; }
}

record Test(int hello);

记录定义是一种速记方式,会扩展为使用init的内容,这就是为什么它也会受到影响的原因。

我上面链接的语言跟踪页面显示该功能已经合并到16.7p3,而我正在使用此版本。

我是不是太兴奋了?我需要等待吗?还是说有办法现在就尝试这些特性:D?

编辑(在评论中请求)- 添加了.net 5.0控制台应用程序的csproj文件:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <LangVersion>preview</LangVersion>
  </PropertyGroup>
</Project>

编辑 #2: 这里发布了一个解决方法 - https://github.com/dotnet/roslyn/issues/45510


你的目标是 .NET Core 5 吗? - Daniel A. White
该问题在 .NET 5.0 控制台应用程序(预览版6)和 .NET Standard 2.1 类库中均出现。 - Josh
".NET Standard 2.1没有这个功能,请发布您的整个csproj文件。" - Daniel A. White
已编辑帖子以包括 csproj 文件。 - Josh
1
有人知道 IsExternalInit 是什么意思吗?只是好奇。 - Qwertie
使用Init,开发者可以引入无效状态,因为他们可以执行类似于 new Test(){Hello=9999}的操作。 - Hieu Le
4个回答

102

当前预览版本和最新的主分支(6月27日)存在一个错误。在sharplab.io中简单的记录也会产生相同的错误。

只需在项目中的某个地方添加缺失的类型即可。

using System.ComponentModel;

namespace System.Runtime.CompilerServices
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    internal class IsExternalInit{}
}

记录和init将正常工作。

只有 LinqPad 6 似乎没有问题,可能是因为它也包含了该类型。


3
当使用TargetFramework为netstandard2.0和LangVersion为9.0时,我遇到了这个错误。使用这个类后问题得以解决。 - Gábor Imre
3
我有5.0的发布版,但它仍然是个问题,真是麻烦。 - Sinaesthetic
2
@PanagiotisKanavos:我和你遇到了同样的问题(只有一个.NET 5.0项目出现了记录声明的问题,而其他很多项目没有)。我发现这种情况发生在引用了其他项目的项目上,其中.NET Standard 2.0与C#9.0功能(如“records”)一起使用。如果我从引用中删除此项目,则错误消失。只要重新添加对该项目的引用,错误就会重新出现。无论您是否已经在旧项目中添加了该类,都必须在当前项目中添加它。 - CesarD
1
非常重要:不要在此声明周围放置#if。有关详细信息,请参见https://twitter.com/aarnott/status/1362786409954766858。 同时,将其设为internal - Andrew Arnott
1
有一个包提供了这个和其他类,这些类是必需的,以便在旧的目标框架中运行新的 C# 特性: PolySharp - cremor
显示剩余6条评论

20

如果您不想在每个项目中都添加 IsExternalInit 类,您可以使用Directory.Build.props 将该文件自动引用为不可见的编译项:

<?xml version="1.0" encoding="utf-8"?>
<Project>
    <ItemGroup>
        <Compile Include="$(MSBuildThisFileDirectory)IsExternalInit.cs" Visible="false" />
    </ItemGroup>
</Project>

IsExternalInit.cs 文件添加到您解决方案的根目录下,并在那里添加/编辑此文件。这样做将自动将该文件添加到您所有的项目中。

相对于您的解决方案的示例文件夹结构:

.
├── Directory.Build.props
├── IsExternalInit.cs
└── Solution.sln

不错的答案,但需要更好地解释: 1-在您的根文件夹(解决方案文件夹)中。创建一个文件夹Directory.Build.props,其中*.pros是其扩展名。 2-编辑此文件并添加: <?xml version="1.0" encoding="utf-8"?> <Project> <ItemGroup> <Compile Include="$(MSBuildThisFileDirectory)IsExternalInit.cs" Visible="false" /> </ItemGroup> </Project> 3-将IsExternalInit.cs文件添加到旁边 - abdelgrib
这适用于MSBuild,但即使VS成功构建了它,也会将其内联标记为错误?(针对.NET FW,LangVersion 9.0) - Kissaki
@Kissaki,我在 Visual Studio 2022 中没有遇到 init 关键字的 IntelliSense 问题。 - Bouke

16

借鉴自Panagiotis Kanavos,您实际上可以将IsExternalInit声明为一条记录(自我实现的预言):

IsExternalInit本身可以作为一个记录声明,这个想法来自Panagiotis Kanavos。

using System.ComponentModel;

namespace System.Runtime.CompilerServices
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    public record IsExternalInit;
}

1
你能解释一下为什么要这样做吗? - HackSlash
1
你能解释一下为什么你会这样做吗? - undefined
因为它仍然解决了问题,感觉就像天才和愚蠢之间的完美平衡。 - mycroes
好的,我想问一下public record相对于internal class有什么优点。看起来它似乎只是将类型作用域缩小到记录类型,同时将可见性作用域增加到外部。这样做是否有益处? - HackSlash
差异微不足道。就范围而言,选择最适合你的。我有时会在一个几乎被解决方案中的任何其他项目引用的项目中使用它,在这种情况下,“public”避免了复制的需要。record基本上是class,所以选择你喜欢的即可。 - mycroes

4

@Brouke的回答很好,我会进一步解释:

1- 在您的根文件夹(解决方案文件夹)中创建一个名为Directory.Build.props的文件,其扩展名为*.props

2- 编辑此文件并添加:

<?xml version="1.0" encoding="utf-8"?>
<Project>
    <ItemGroup>
        <Compile Include="$(MSBuildThisFileDirectory)IsExternalInit.cs" Visible="false" />
    </ItemGroup>
</Project>

3 - 将 IsExternalInit.cs 文件与此文件一起添加,并包含以下内容:

using System.ComponentModel;

namespace System.Runtime.CompilerServices
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    public record IsExternalInit;
}

4 - 删除所有其他的 IsExternalInit.cs 文件,重新构建解决方案并重启 VS。


如果您将其添加到解决方案中的每个项目中,将其设置为“公共”的做法就没有意义。 - mycroes
1
你是指 .props 而不是 .pros,对吗? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接