Захотел я идти в ногу со временем, посмотрел новые фишки и плюшки 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-ом? Что можно сделать и как?
Да, можно использовать новые версии, но с оговорочкой...об этом ниже.
Хоть 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
) в свой проект./CSharp60Support/ngen install.cmd
с правами администратора. Команда скомпилирует csc.exe, pdb2mdb.exe и mcs.exe используя Ngen, что позволит производить компилирование в Unity чуточку быстрее.Для C# 7.0
CSharp70Support
из репозитория (или со страницы закачки) к себе в Unity проект. Папку необходимо поместить в корень проекта, рядом с папкой Assets
. НЕ во внутрь!CSharp70Support.unitypackage
(находится в папке CSharp70Support
) в свой проект./CSharp70Support/ngen install.cmd
с правами администратора. Команда скомпилирует 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
Работает это на всех основных платформах:
Чуть больше информации и небольших ограничениях вы можете почитать на главной странице репозитория, а также (т.к. основная информация дана выше) в виде цитаты с источника на английском языке:
Response (.rsp) filesIf you want to use a response file to pass extra options to the compiler (e.g. -unsafe
), the file must be named CSharpCompilerWrapper.rsp
.
On MacOS the Roslyn compiler cannot create debug information files (.pdb) that 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 issuesC# 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<int>
. However, bar
's type is deduced correctly -
Nullable<int>
.
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 notesRoslyn 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 and how to use it, see this set of articles by Stephen Toub: one, two, three.
P.S. Попробую отслеживать тему и держать ссылку на свежую версию актуальной.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Как корректно обработать исключение Format Exception на проверку введенных значений в TextBox?