如何在Unity3D项目上启用c#7功能

Nad*_*310 6 c# project unity-game-engine visual-studio c#-7.0

我在Unity3D项目中编写了一个新方法(使用Visual Studio 2017),对于该方法,我需要C#7或更高版本.所以我按照本指南中的说明操作.

现在,当我尝试打开项目的属性时,Visual Studio会打开它,但随后它会在打开后立即关闭.现在我甚至无法打开项目的属性.

这是它的样子:

GIF

为什么我会收到第一个和第三个错误?(我在gif中展示的那些)

sɐu*_*qɐp 8

编辑

Unity 2018.3现在支持Roslyn编译器,允许您使用最新的C#7功能!

请参阅:https://blogs.unity3d.com/2018/09/13/unity-2018-3-beta-get-early-access-now/


对于Unity3D <2018.3.*

我将告诉你我是如何在Unity3D项目中启用C#7.3的(虽然它的某些功能还无法编译).但要注意:这种方法很糟糕!这是Unity中C#7的过早和实验性使用.

如果您按照以下说明操作,我相信您可以轻松找到问题,因为在您的问题中,为SO社区提供完整的MCVE非常困难.但我相信你实际想要实现的是为Unity启用C#7,而不是解决项目属性窗口中的奇怪错误.

在继续之前,我建议完全重新安装Visual Studio 2017和Unity3D,以确保您没有任何与错误安装相关的问题.始终直接从Unity的网页下载Unity,而不是使用Viual Studio的安装程序,因此您可以获得最新版本.

在Unity 3D项目中启用C#7(在Unity3D v.2018.2.10f,VS 2017 v.15.8.5上测试)

  1. 首先创建一个新的空项目.

  2. 转到Edit -> Project Settings -> Player,找到该Other Settings部分,然后在Configuration/ Scripting Runtime Version选择下.NET 4.x Equivalent.

  3. 我们想告诉mcs.exe使用C#7的新"实验"功能处理C#代码.为此,只需mcs.rsp在Assets文件夹中创建文件即可.编辑它并在其中写下这一行:

    -langversion:experimental
    
    Run Code Online (Sandbox Code Playgroud)
  4. 现在,创建一个名为EditorAssets文件夹内的新文件夹.添加到此文件夹的任何脚本都将使Unity创建一个*.Editor.csproj项目文件,该文件包含旨在修改Unity编辑器的脚本.

  5. 我们需要告诉Visual Studio您的项目支持C#7.3语言.这并不意味着Unity将能够编译C#7.3的所有功能,但至少Visual Studio不会讨论您尝试使用的功能.

    但是,如果csproj直接编辑文件,Unity会在某个时刻自动覆盖它(Unity总是自动生成项目和解决方案文件).所以你可以做的是安装一个在自动生成项目文件时调用的钩子,这样你就可以自己打开项目文件并添加你的自定义(你的自定义不仅限于更改语言版本:你可以做更多的事情,但你必须明白你在做什么).

    为此,将以下脚本放在Editor文件夹中:

    #if ENABLE_VSTU
    
    using SyntaxTree.VisualStudio.Unity.Bridge;
    using System;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;
    using UnityEditor;
    using UnityEngine;
    
    [InitializeOnLoad]
    public class ProjectFilesGeneration
    {
        private class Utf8StringWriter : StringWriter
        {
            public override Encoding Encoding
            {
                get { return Encoding.UTF8; }
            }
        }
    
        static ProjectFilesGeneration()
        {
            ProjectFilesGenerator.ProjectFileGeneration += (string name, string content) =>
            {
                // Ignore projects you do not want to edit here:
                if (name.EndsWith("Editor.csproj", StringComparison.InvariantCultureIgnoreCase)) return content;
    
                Debug.Log($"CUSTOMIZING PROJECT FILE: '{name}'");
    
                // Load csproj file:
                XNamespace ns = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");
                XDocument xml = XDocument.Parse(content);
    
                // Find all PropertyGroups with Condition defining a Configuration and a Platform:
                XElement[] nodes = xml.Descendants()
                    .Where(child =>
                        child.Name.LocalName == "PropertyGroup"
                        && (child.Attributes().FirstOrDefault(attr => attr.Name.LocalName == "Condition")?.Value.Contains("'$(Configuration)|$(Platform)'") ?? false)
                    )
                    .ToArray();
    
                // Add <LangVersion>7.3</LangVersion> to these PropertyGroups:
                foreach (XElement node in nodes)
                    node.Add(new XElement(ns + "LangVersion", "7.3"));
    
                // Write to the csproj file:
                using (Utf8StringWriter str = new Utf8StringWriter())
                {
                    xml.Save(str);
                    return str.ToString();
                }
            };
        }
    }
    
    #endif
    
    Run Code Online (Sandbox Code Playgroud)

如果要完全了解项目文件中的更改,只需使用任何diff工具,即可比较以前的版本和csproj文件的新版本.上面的hack基本上做了类似于你在更改语言版本时发布的链接,除了每次Unity自动生成项目文件时都会这样做.Microsoft还提供了大量有关文件内部定义的csproj文档.


Mar*_*Pim 0

属性窗口未打开听起来像是 Visual Studio 安装的一些问题(对此我无法提供太多建议)

对于编码错误,看起来您正在尝试在另一个方法中声明一个方法(这很奇怪):

void Update() {
    ...
    public void Method1();
}
Run Code Online (Sandbox Code Playgroud)

这不是你的本意。它会抱怨,因为您正在编译的 C# 版本不支持这一点(并且在任何情况下都无法标记 C#7 中的本地方法public)。它还会抱怨,因为你的方法不是抽象的(或外部的),但没有主体,这是 C# 不允许的。这是你的意思吗?

void Update() {
    if (Input.GetKeyDown(KeyCode.R)) // Note no ; here!
    {
        GetComponent<Renderer>().material.color = Color.red;
    }
}

public void Method1() {
    // Some code
}
Run Code Online (Sandbox Code Playgroud)

;另外,第 15 行的语句后出现错误。if ()这将导致该GetComponent<Renderer>行(第 17 行)始终运行,而不仅仅是条件为真时运行。再说一遍,这可能不是你想象的那样。