Захотел я идти в ногу со временем, посмотрел новые фишки и плюшки C#6/7, воодушевился
Там так всё вкусно и круто, что грех не пользоваться. Открыл Unity, Visual Studio, написал пару строк и...впал в уныние. На любые попытки использования новых фич мне говорят одно:
Feature bla bla bla is not available in C#4. Please use language version 6 or greater
или
Feature bla bla bla cannot be used because it is not part of the C# 4.0 language specification
Посмотрел версию Mono, которую использует Unity 5.6 (!!! самая последняя версия
и это было: 2.0 (Visual Studio built mono). В итоге в ней есть всё, что есть в C#3, плюс часть из C#4.
Это меня не очень радует и устраивает.
Есть ли какая возможность, всё-таки, использовать новые версии языка, а не застыть в далёком 2010-ом? Что можно сделать и как?
Ответы
Ответ 1
Да, можно использовать новые версии, но с оговорочкой...об этом ниже.
Хоть Unity и застряла на долгое время на CLR 2.0, тем не менее новые фичи C# не требую
самой последней версии CLR. Компиляторы Microsoft и Mono могут скомпилировать C# 5/6/7 для CLR 2.0 если их явно об этом попросить.
Замечание: однако некоторые фичи все же недоступны, например такие как dynamic.
Итак, эту возможность (и, на данный момент, может быть единственную) можно найт
в репозитории битбакета Unity C# 5.0 and 6.0 Integration
Что надо сделать?
Для C# 6.0
Скопировать папку CSharp60Support из репозитория (или со страницы закачки) к себ
в Unity проект. Папку необходимо поместить в корень проекта, рядом с папкой Assets. НЕ во внутрь!
Импортировать CSharp60Support.unitypackage (находится в папке CSharp60Support)
свой проект.
Перезагрузить Unity
[По желанию - не обязательно]: На Windows - запустить /CSharp60Support/ngen install.cm
с правами администратора. Команда скомпилирует csc.exe, pdb2mdb.exe и mcs.exe используя Ngen, что позволит производить компилирование в Unity чуточку быстрее.
Для C# 7.0
Для MacOS скачать и установить Mono 4.6+. Для Windows скачать и установить .Net Framework 4.6.2+.
Скопировать папку CSharp70Support из репозитория (или со страницы закачки) к себ
в Unity проект. Папку необходимо поместить в корень проекта, рядом с папкой Assets. НЕ во внутрь!
Импортировать CSharp70Support.unitypackage(находится в папке CSharp70Support) в свой проект.
Перезагрузить Unity
[По желанию - не обязательно] На Windows - запустить /CSharp70Support/ngen install.cm
с правами администратора. Команда скомпилирует csc.exe, pdb2mdb.exe и mcs.exe используя Ngen, что позволит производить компилирование в Unity чуточку быстрее.
Таким образом изменению подвергается только папка с текущим проектом. Остальные проекты будут работать как обычно с текущей версией языка, Mono и прочей жестью :)
Как это работает?
/Assets/CSharp vNext Support/Editor/CSharpVNextSupport.dll - расширение для редактора
которое через рефлексию изменяет внутренние данные редактора, говоря ему, чтобы тот использовал альтернативный компилятор C# (/CSharpXXSupport/CSharpCompilerWrapper.exe). Если он не существует, то используется дефолтный.
CSharpCompilerWrapper.exe получает и перенаправляет запросы на компиляцию от Unity к одному из актуальных C# компиляторов, которые используют следующие правила:
Если существует папка CSharp70Support и она содержит папку Roslyn, то используется компилятор C# 7.0;
Если существует папка CSharp60Support и она содержит папку Roslyn, то используется компилятор C# 6.0;
Иначе если существует папка CSharp60Support и она содержит mcs.exe, то использует компилятор Mono C# 6.0;
В ином случае используется компилятор по дефолту (/Unity/Editor/Data/Mono/lib/mono/2.0/gmcs.exe).
Убедитесь, что компилятор CSharpCompilerWrapper.exe действительно работает! Для этого посмотрите в логи компиляции: UnityProject/CSharpXXSupport/compilation.log
Какие платформы поддерживаются?
Работает это на всех основных платформах:
Windows (editor and standalone)
MacOS (editor and standalone)
Android
iOS
Чуть больше информации и небольших ограничениях вы можете почитать на главной страниц
репозитория, а также (т.к. основная информация дана выше) в виде цитаты с источника на английском языке:
Response (.rsp) files
If you want to use a response file to pass extra options to the compiler (e.g
-unsafe), the file must be named CSharpCompilerWrapper.rsp.
platforms are "supported"
On MacOS the Roslyn compiler cannot create debug information files (.pdb) tha
Unity can consume. If you compile your code with Roslyn on MacOS you won't be able to debug it.
Since WebGL doesn't offer any multithreading support, AsyncBridge and
Task Parallel Library are not available for this platform. Caller Info
attributes are also not available, because their support comes with
AsyncBridge library.
AsyncBridge/TPL stuff is also not compatible with Windows Store
Application platform (and probably all the platforms that use .Net
runtime instead of Mono runtime) due to API differences between the
recent versions of .Net Framework and the ancient version of TPL
(System.Threading.dll) that comes with AsyncBridge. Namely, you can't
use async/await, Caller Info attributes and everything from
System.Threading.dll (concurrent collections for example).
Other known issues
C# 5.0/6.0 is not compatible with Unity Cloud Build service for obvious reason.
Using Mono C# 6.0 compiler may cause occasional Unity crashes while debugging in Visual Studio -
http://forum.unity3d.com/threads/c-6-0.314297/page-2#post-2225696
IL2CPP doesn't support exception filters added in C# 6.0 (ExceptionFiltersTest.cs).
If a MonoBehaviour is declared inside a namespace, the source file should not contain any C# 6.0-specific language constructions before
the MonoBehaviour declaration. Otherwise, the editor won't recognize
the script as a MonoBehaviour component.
Bad example:
using UnityEngine;
using static System.Math; // C# 6.0 syntax!
namespace Foo
{
class Baz
{
object Qux1 => null; // C# 6.0 syntax!
object Qux2 { get; } = null; // C# 6.0 syntax!
}
class Bar : MonoBehaviour { } // "No MonoBehaviour scripts in the file, or their names do not match the file name."
}
Good example:
using UnityEngine;
namespace Foo
{
class Bar : MonoBehaviour { } // ok
class Baz
{
object Qux1 => null;
object Qux2 { get; } = null;
}
}
There's a bug in Mono C# 6.0 compiler, related to null-conditional operator support (NullConditionalTest.cs):
var foo = new[] { 1, 2, 3 };
var bar = foo?[0];
Debug.Log((foo?[0]).HasValue); // error CS1061: Type `int' does not
// contain a definition for `HasValue' and no extension method
// `HasValue' of type `int' could be found. Are you missing an
// assembly reference?
Mono compiler thinks that foo?[0] is int while it's actually Nullable. However, bar's type is deduced correctly -
Nullable.
License
All the source code is published under WTFPL version
2.
Want to talk about it?
http://forum.unity3d.com/threads/c-6-0.314297/#post-2108999
Random notes
Roslyn C# 6.0 compiler was taken from VS 2015 installation. C# 7.0 compiler was taken from VS 15 Preview 5 installation.
mcs.exe, pdb2mdb.exe and its dependencies were taken from Mono 4.4.1.0 installation
pdb2mdb.exe that comes with Unity is not compatible with the assemblies generated with Roslyn compiler.
AsyncBridge library contains a set of types that makes it possible to use async/await in projects that target CLR 2.0. It also provides
Caller Info attributes support. For more information, check this blog
post.
If you use async/await inside Unity events (Awake, Start, Update etc) you may notice that continuations (the code below await
keyword) are executed in background threads. Most likely, this is not
what you would want. To force await to return the execution to the
main thread, you'll have to provide it with a synchronization context,
like all WinForms and WPF applications do.
Check UnityScheduler.cs, UnitySynchronizationContext.cs and UnityTaskScheduler.cs example implementations located in the
project. These classes create and register several synchronization
contexts for the Unity's main thread, so async/await could work the
way they do in regular WinForms or WPF applications.
For more information about what synchronization context is, what it is for an
how to use it, see this set of articles by Stephen Toub:
one, two, three.
P.S. Попробую отслеживать тему и держать ссылку на свежую версию актуальной.
Комментариев нет:
Отправить комментарий