之前我在知乎问过相关问题,后面参考了几个知友的回答,借鉴了一些项目,也算是基本解决了这个问题
也顺便附上我的知乎回答:https://www.zhihu.com/question/11672499668/answer/103930816515
以下是关于如何在 Unity 中使用更高版本的 C# 特性的详细解决办法(具有一定局限性)
Comfirm the C# version that Unity supports
关于你的 unity editor 本身能够支持到多高的 C# 版本,以我的 unity 2022.3.52f1c1 为例,去 unity editor 所在的目录下面这个路径,打开 README 里面有 dotnet sdk 版本

然后去官方搜索一下该版本的相关信息:

发现可以支持到 C#10,在这个版本中,C#处于可预览状态,如果是一般的 cs 项目(使用该 sdk),可以直接在 csproj 指定 <LangVersion>preview</LangVersion>
来使用部分的 C#11 特性。
但是 Unity 中的所谓 C# 项目并不是这么一回事,项目根目录里面的一堆 .csproj 文件,只是 Unity 自动生成给 IDE 看的,这也是为什么用 Rider,VSCode 之类的 IDE 打开项目后能进行解析()
Unity Compile
在官方手册里面有关于这个的说明:Unity editor 会指定默认的编译选项给后端的 Roslyn 编译器(也就是C#版本指定 9.0)

不过后面也说明了可以传递别的参数(),于是可以在这篇文章找到答案,用户可以在 Assets/ 目录下添加 csc.rsp 文件来指定编译参数,文档给的例子是在 .rsp 文件里通过 -define:XXXX
来定义宏,用以条件编译。
但是我们显然能玩点别的东西,比如指定 -langversion
,按照前文的思路,我们可以启用 C#11 的部分特性。
所以我们创建一个 csc.rsp
文件放在 Assets/ 目录下(或者你的程序集的同目录),写入以下内容:
1 | -langversion:preview -nullable |
这些指令是将语言版本设置为预览状态,然后启用nullable编译
关于后者,你可以在代码中使用 ? 来声明一个类型可为 null,比如:
1
2
3
4 public struct Example
{
public int? ValueInt;
}如果不启用的 nullable,使用 ? 会警告你 “需要在 #nullable 的上下文使用”。
然后你可以在你的脚本里面使用 C#11 的特性,回到 UnityEditor 中看看能不能通过编译。以下是一段简单的测试代码:
1 | public struct DefaultValue |
如果你使用的较新的 unity 2022.3 (>= 2022.3.12f1)那么这段代码是可以通过编译的(当然你也可以整个 mono 类去创建这两个 struct 输出确认是否真的设置成了指定的默认值)
不过你在编写上述代码的时候,IDE 里面一定是一片爆红吧 :laughing: 。
不用担心,让 csproj 来救你(x
Change .csproj files
在前面有说过,Unity 项目根目录的 .csproj 文件都是给 IDE 看的,你可以随便打开一个 .csproj 文件,里面应该很容易找到一行内容是:<LangVersion>9.0</LangVersion>
这会导致你的 IDE 会认为你的项目使用 C#9 ,所以前面编写 C#11 的代码的时候自然是会报错的啦(),你可以手动修改一下文件试试。
尝试将你的 Assembly-CSharp.csproj
文件里面的 langversion 那一行改成 <LangVersion>preview</LangVersion>
如果你使用程序集,比如有一个
My.Test.asmdef
的程序集,那么 UnityEditor 会自动给这个程序集生成一个My.Test.csproj
(当然也是在项目根目录),那么 IDE 对该程序集中的代码的解析,就会受到My.Test.csproj
的影响,这时候需要去修改My.Test.csproj
里面的 langversion 选项了()
回到你的 IDE 里面应该就不会报错了。
当然每次编译后,unity 都会重新生成一遍,所以建议写个脚本,读取 csproj, 然后修改相关的选项,然后可以监听 compilationFinished
事件自动执行。
Some lunatic ideas for higher version (P.S.)
还有一些本人没有实践过的想法,有些已经被别人尝试过,有些不确定有没有人试过,感兴趣的可以玩玩 :laughing:
- 开一个 C# 项目,目标框架设置
<TargetFramework>netstandard2.1</TargetFramework>
,然后语言版本设置<TargetFramework>latest</TargetFramework>
,应该能够使用到 C#12 甚至更高的特性,当然部分特性可能缺少预定义类,可以通过 PolySharp 来补充(),详情可以参考 R3 项目。 - 修改你的 Unity Editor 的 Roslyn 编译器依赖的 SDK 版本(?)(如果要尝试建议备份一下)