Wytyczne dotyczące kodowania — MRTK2

W tym dokumencie opisano zasady kodowania i konwencje, które należy przestrzegać podczas współtworzenia zestawu narzędzi MRTK.


Filozofii

Bądź zwięzły i dążyć do uproszczenia

Najprostsze rozwiązanie jest często najlepsze. Jest to nadrzędny cel tych wytycznych i powinien być celem wszystkich działań kodowania. Część bycia prostym jest zwięzła i spójna z istniejącym kodem. Spróbuj zachować prostotę kodu.

Czytelnicy powinni napotkać tylko artefakty, które dostarczają przydatnych informacji. Na przykład komentarze, które przedstawiają, co jest oczywiste, nie zawierają dodatkowych informacji i zwiększają współczynnik szumu do sygnału.

Zachowaj prostotę logiki kodu. Należy pamiętać, że nie jest to instrukcja dotycząca używania najmniejszej liczby wierszy, minimalizacji rozmiaru nazw identyfikatorów lub stylu nawiasu klamrowego, ale zmniejszenie liczby pojęć i maksymalizacja widoczności tych wierszy za pomocą znanych wzorców.

Tworzenie spójnego, czytelnego kodu

Czytelność kodu jest skorelowana z niskimi współczynnikami wad. Staraj się tworzyć kod, który jest łatwy do odczytania. Staraj się tworzyć kod, który ma prostą logikę i ponownie używa istniejących składników, ponieważ pomoże również zapewnić poprawność.

Wszystkie szczegóły kodu, który tworzysz, mają znaczenie, od najbardziej podstawowych szczegółów poprawności po spójny styl i formatowanie. Zachowaj spójność stylu kodowania z tym, co już istnieje, nawet jeśli nie pasuje do preferencji. Zwiększa to czytelność ogólnej bazy kodu.

Obsługa konfigurowania składników zarówno w edytorze, jak i w czasie wykonywania

Zestaw narzędzi MRTK obsługuje zróżnicowany zestaw użytkowników — osoby, które wolą konfigurować składniki w edytorze aparatu Unity i ładować prefabrykaty, oraz osoby, które muszą utworzyć wystąpienie i skonfigurować obiekty w czasie wykonywania.

Cały kod powinien działać przez dodanie składnika do obiektu GameObject w zapisanej scenie i utworzenie wystąpienia tego składnika w kodzie. Testy powinny zawierać przypadek testowy zarówno do tworzenia wystąpień prefab, jak i tworzenia wystąpień, konfigurowania składnika w czasie wykonywania.

Play-in-editor to twoja pierwsza i podstawowa platforma docelowa

Play-In-Editor to najszybszy sposób iteracji w afiszacie Unity. Zapewnienie klientom sposobów szybkiego iterowania pozwala im szybciej opracowywać rozwiązania i wypróbować więcej pomysłów. Innymi słowy, maksymalizacja szybkości iteracji pozwala naszym klientom osiągnąć więcej.

Utwórz wszystko, co działa w edytorze, a następnie sprawi, że będzie działać na dowolnej innej platformie. Zachowaj to działanie w edytorze. Dodanie nowej platformy do edytora play-in-editor jest łatwe. Bardzo trudno jest uruchomić edytor play-in-Editor, jeśli aplikacja działa tylko na urządzeniu.

Dodaj nowe pola publiczne, właściwości, metody i serializowane pola prywatne z ostrożnością

Za każdym razem, gdy dodajesz metodę publiczną, pole, właściwość, staje się ona częścią publicznej powierzchni interfejsu API zestawu narzędzi MRTK. Pola prywatne oznaczone również polami [SerializeField] uwidaczniają edytor i są częścią publicznej powierzchni interfejsu API. Inne osoby mogą używać tej metody publicznej, konfigurować niestandardowe prefabryki z polem publicznym i brać od niego zależność.

Należy dokładnie zbadać nowych członków społeczeństwa. Wszystkie pola publiczne będą musiały być utrzymywane w przyszłości. Należy pamiętać, że jeśli typ pola publicznego (lub serializowane pole prywatne) ulegnie zmianie lub zostanie usunięty z monoBehaviour, może to spowodować przerwanie innych osób. Pole musi najpierw zostać uznane za przestarzałe dla wydania, a kod w celu przeprowadzenia migracji zmian dla osób, które podjęły zależności, muszą zostać podane.

Określanie priorytetów podczas pisania testów

MRTK to projekt społeczności, zmodyfikowany przez różnorodnych współautorów. Ci współautorzy mogą nie znać szczegółów poprawki/funkcji usterki i przypadkowo przerwać funkcję. Zestaw narzędzi MRTK uruchamia testy ciągłej integracji przed ukończeniem każdego żądania ściągnięcia. Nie można zaewidencjonować zmian, które przerywają testy. W związku z tym testy są najlepszym sposobem zapewnienia, że inne osoby nie przerywają działania funkcji.

Po naprawieniu usterki napisz test, aby upewnić się, że nie będzie on regresji w przyszłości. W przypadku dodawania funkcji należy napisać testy sprawdzające, czy funkcja działa. Jest to wymagane dla wszystkich funkcji środowiska użytkownika z wyjątkiem funkcji eksperymentalnych.

Konwencje kodowania w języku C#

Nagłówki informacji o licencji skryptu

Wszyscy pracownicy firmy Microsoft współtworzenia nowych plików powinni dodać następujący standardowy nagłówek licencji w górnej części wszystkich nowych plików, dokładnie tak jak pokazano poniżej:

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

Nagłówki podsumowania funkcji/metody

Wszystkie klasy publiczne, struktury, wyliczenia, funkcje, właściwości, pola opublikowane w obiekcie MRTK powinny być opisane jako jej przeznaczenie i użycie, dokładnie tak jak pokazano poniżej:

/// <summary>
/// The Controller definition defines the Controller as defined by the SDK / Unity.
/// </summary>
public struct Controller
{
    /// <summary>
    /// The ID assigned to the Controller
    /// </summary>
    public string ID;
}

Dzięki temu dokumentacja jest prawidłowo generowana i rozpowszechniana dla wszystkich klas, metod i właściwości.

Wszystkie pliki skryptów przesłane bez odpowiednich tagów podsumowania zostaną odrzucone.

Reguły przestrzeni nazw zestawu narzędzi MRTK

Zestaw narzędzi Mixed Reality używa modelu przestrzeni nazw opartej na funkcjach, w którym wszystkie podstawowe przestrzenie nazw zaczynają się od "Microsoft.MixedReality.Toolkit". Ogólnie rzecz biorąc, nie trzeba określać warstwy zestawu narzędzi (np. Core, Providers, Services) w przestrzeniach nazw.

Obecnie zdefiniowane przestrzenie nazw to:

  • Microsoft.MixedReality.Toolkit
  • Microsoft.MixedReality.Toolkit.Boundary
  • Microsoft.MixedReality.Toolkit.Diagnostics
  • Microsoft.MixedReality.Toolkit.Editor
  • Microsoft.MixedReality.Toolkit.Input
  • Microsoft.MixedReality.Toolkit.SpatialAwareness
  • Microsoft.MixedReality.Toolkit.Teleport
  • Microsoft.MixedReality.Toolkit.Utilities

W przypadku przestrzeni nazw z dużą ilością typów dopuszczalne jest utworzenie ograniczonej liczby przestrzeni nazw podrzędnych, aby ułatwić określanie zakresu użycia.

Pominięcie przestrzeni nazw dla interfejsu, klasy lub typu danych spowoduje zablokowanie zmiany.

Dodawanie nowych skryptów MonoBehaviour

Podczas dodawania nowych skryptów MonoBehaviour z żądaniem ściągnięcia upewnij się, że AddComponentMenu atrybut jest stosowany do wszystkich odpowiednich plików. Dzięki temu składnik jest łatwo wykrywalny w edytorze w obszarze przycisku Dodaj składnik . Flaga atrybutu nie jest konieczna, jeśli składnik nie może być wyświetlany w edytorze, takim jak klasa abstrakcyjna.

W poniższym przykładzie pakiet powinien zostać wypełniony lokalizacją pakietu składnika. W przypadku umieszczenia elementu w folderze ZESTAWU MRTK/SDK pakiet będzie zestawem SDK.

[AddComponentMenu("Scripts/MRTK/{Package here}/MyNewComponent")]
public class MyNewComponent : MonoBehaviour

Dodawanie nowych skryptów inspektora aparatu Unity

Ogólnie rzecz biorąc, staraj się unikać tworzenia skryptów inspektora niestandardowego dla składników zestawu narzędzi MRTK. Dodaje dodatkowe nakłady pracy i zarządzanie bazą kodu, która może być obsługiwana przez aparat aparatu Unity.

Jeśli wymagana jest klasa inspector, spróbuj użyć aparatu DrawDefaultInspector()Unity . To ponownie upraszcza klasę inspektora i pozostawia wiele pracy dla Aparatu Unity.

public override void OnInspectorGUI()
{
    // Do some custom calculations or checks
    // ....
    DrawDefaultInspector();
}

Jeśli renderowanie niestandardowe jest wymagane w klasie inspector, spróbuj użyć SerializedProperty elementów i EditorGUILayout.PropertyField. Dzięki temu aparat Unity poprawnie obsługuje renderowanie zagnieżdżonych prefabów i zmodyfikowanych wartości.

Jeśli EditorGUILayout.PropertyField nie można używać z powodu wymagania w logice niestandardowej, upewnij się, że całe użycie jest opakowane wokół elementu EditorGUI.PropertyScope. Zapewni to, że aparat Unity poprawnie renderuje inspektora dla zagnieżdżonych prefab i zmodyfikowanych wartości z daną właściwością.

Ponadto spróbuj ozdobić klasę inspektora niestandardowego za pomocą klasy CanEditMultipleObjects. Ten tag zapewnia, że można wybrać i zmodyfikować wiele obiektów z tym składnikiem w scenie. Wszystkie nowe klasy inspektorów powinny sprawdzić, czy ich kod działa w tej sytuacji w scenie.

    // Example inspector class demonstrating usage of SerializedProperty & EditorGUILayout.PropertyField
    // as well as use of EditorGUI.PropertyScope for custom property logic
    [CustomEditor(typeof(MyComponent))]
    public class MyComponentInspector : UnityEditor.Editor
    {
        private SerializedProperty myProperty;
        private SerializedProperty handedness;

        protected virtual void OnEnable()
        {
            myProperty = serializedObject.FindProperty("myProperty");
            handedness = serializedObject.FindProperty("handedness");
        }

        public override void OnInspectorGUI()
        {
            EditorGUILayout.PropertyField(destroyOnSourceLost);

            Rect position = EditorGUILayout.GetControlRect();
            var label = new GUIContent(handedness.displayName);
            using (new EditorGUI.PropertyScope(position, label, handedness))
            {
                var currentHandedness = (Handedness)handedness.enumValueIndex;

                handedness.enumValueIndex = (int)(Handedness)EditorGUI.EnumPopup(
                    position,
                    label,
                    currentHandedness,
                    (value) => {
                        // This function is executed by Unity to determine if a possible enum value
                        // is valid for selection in the editor view
                        // In this case, only Handedness.Left and Handedness.Right can be selected
                        return (Handedness)value == Handedness.Left
                        || (Handedness)value == Handedness.Right;
                    });
            }
        }
    }

Dodawanie nowych obiektów ScriptableObjects

Podczas dodawania nowych skryptów ScriptableObject upewnij się, że CreateAssetMenu atrybut jest stosowany do wszystkich odpowiednich plików. Dzięki temu składnik jest łatwo wykrywalny w edytorze za pośrednictwem menu tworzenia zasobów. Flaga atrybutu nie jest konieczna, jeśli składnik nie może być wyświetlany w edytorze, takim jak klasa abstrakcyjna.

W poniższym przykładzie podfolder powinien zostać wypełniony podfolderem zestawu narzędzi MRTK, jeśli ma to zastosowanie. W przypadku umieszczenia elementu w folderze MRTK/Providers pakiet będzie dostawcą. W przypadku umieszczenia elementu w folderze MRTK/Core ustaw tę opcję na "Profile".

W poniższym przykładzie myNewService | Element MyNewProvider powinien być wypełniony nazwą nowej klasy, jeśli ma to zastosowanie. W przypadku umieszczenia elementu w folderze MixedRealityToolkit pozostaw ten ciąg na wyjściu.

[CreateAssetMenu(fileName = "MyNewProfile", menuName = "Mixed Reality Toolkit/{Subfolder}/{MyNewService | MyNewProvider}/MyNewProfile")]
public class MyNewProfile : ScriptableObject

Rejestrowanie

Podczas dodawania nowych funkcji lub aktualizowania istniejących funkcji rozważ dodanie dzienników DebugUtilities.LogVerbose do interesującego kodu, który może być przydatny do przyszłego debugowania. Istnieje kompromis między dodawaniem rejestrowania a dodanym szumem i niewystarczającą ilością rejestrowania (co sprawia, że diagnoza jest trudna).

Interesujący przykład, w którym rejestrowanie jest przydatne (wraz z interesującym ładunkiem):

DebugUtilities.LogVerboseFormat("RaiseSourceDetected: Source ID: {0}, Source Type: {1}", source.SourceId, source.SourceType);

Ten typ rejestrowania może pomóc w przechwyceniu problemów, takich jak https://github.com/microsoft/MixedRealityToolkit-Unity/issues/8016, które zostały spowodowane niezgodnością wykrytego źródła i utraconych zdarzeń źródła.

Unikaj dodawania dzienników dla danych i zdarzeń występujących w każdej ramce — w idealnym przypadku rejestrowanie powinno obejmować zdarzenia "interesujące" oparte na odrębnych danych wejściowych użytkownika (tj. "kliknięcie" przez użytkownika oraz zestaw zmian i zdarzeń, które pochodzą z tych danych, które są interesujące do rejestrowania). Bieżący stan "użytkownik nadal trzyma gest" rejestrowany przez każdą ramkę nie jest interesujący i przytłoczy dzienniki.

Należy pamiętać, że to pełne rejestrowanie nie jest domyślnie włączone (musi być włączone w ustawieniach systemu diagnostycznego)

Spacje a karty

Pamiętaj, aby używać 4 spacji zamiast kart podczas współtworzenia tego projektu.

Odstępy

Nie należy dodawać dodatkowych spacji między nawiasami kwadratowymi i nawiasami:

Zakazy

private Foo()
{
    int[ ] var = new int [ 9 ];
    Vector2 vector = new Vector2 ( 0f, 10f );
}

Zalecenia

private Foo()
{
    int[] var = new int[9];
    Vector2 vector = new Vector2(0f, 10f);
}

Konwencje nazewnictwa

Zawsze używaj PascalCase właściwości. Jest używany camelCase w przypadku większości pól, z wyjątkiem pól PascalCasestatic readonly i const . Jedynym wyjątkiem jest to, że w przypadku struktur danych, które wymagają serializacji pól przez JsonUtilityobiekt .

Zakazy

public string myProperty; // <- Starts with a lowercase letter
private string MyField; // <- Starts with an uppercase letter

Zalecenia

public string MyProperty;
protected string MyProperty;
private static readonly string MyField;
private string myField;

Modyfikatory dostępu

Zawsze deklaruj modyfikator dostępu dla wszystkich pól, właściwości i metod.

  • Wszystkie metody interfejsu API aparatu Unity powinny być private domyślnie, chyba że trzeba je zastąpić w klasie pochodnej. W tym przypadku protected należy użyć.

  • Pola powinny zawsze mieć privatewartość , z akcesorami public właściwości lub protected .

  • Używanie elementów członkowskich wyrażeń i właściwości automatycznych , jeśli to możliwe

Zakazy

// protected field should be private
protected int myVariable = 0;

// property should have protected setter
public int MyVariable => myVariable;

// No public / private access modifiers
void Foo() { }
void Bar() { }

Zalecenia

public int MyVariable { get; protected set; } = 0;

private void Foo() { }
public void Bar() { }
protected virtual void FooBar() { }

Używanie nawiasów klamrowych

Zawsze używaj nawiasów klamrowych po każdym bloku instrukcji i umieszczaj je w następnym wierszu.

Zakazy

private Foo()
{
    if (Bar==null) // <- missing braces surrounding if action
        DoThing();
    else
        DoTheOtherThing();
}

Zakazy

private Foo() { // <- Open bracket on same line
    if (Bar==null) DoThing(); <- if action on same line with no surrounding brackets
    else DoTheOtherThing();
}

Zalecenia

private Foo()
{
    if (Bar==true)
    {
        DoThing();
    }
    else
    {
        DoTheOtherThing();
    }
}

Klasy publiczne, struktury i wyliczenia powinny znajdować się we własnych plikach

Jeśli klasa, struktura lub wyliczenie mogą być prywatne, można go dołączyć do tego samego pliku. Pozwala to uniknąć problemów z kompilacjami aparatu Unity i zapewnienia, że występuje właściwa abstrakcja kodu, zmniejsza również konflikty i zmiany powodujące niezgodność, gdy kod musi ulec zmianie.

Zakazy

public class MyClass
{
    public struct MyStruct() { }
    public enum MyEnumType() { }
    public class MyNestedClass() { }
}

Zalecenia

 // Private references for use inside the class only
public class MyClass
{
    private struct MyStruct() { }
    private enum MyEnumType() { }
    private class MyNestedClass() { }
}

Zalecenia

MyStruct.cs

// Public Struct / Enum definitions for use in your class.  Try to make them generic for reuse.
public struct MyStruct
{
    public string Var1;
    public string Var2;
}

MyEnumType.cs

public enum MuEnumType
{
    Value1,
    Value2 // <- note, no "," on last value to denote end of list.
}

MyClass.cs

public class MyClass
{
    private MyStruct myStructReference;
    private MyEnumType myEnumReference;
}

Inicjowanie wyliczenia

Aby upewnić się, że wszystkie wyliczenia są inicjowane poprawnie, począwszy od 0, platforma .NET daje ci uporządkowany skrót do automatycznego inicjowania wyliczenia, dodając tylko pierwszą (starter) wartość. (np. Wartość 1 = 0 Pozostałe wartości nie są wymagane)

Zakazy

public enum Value
{
    Value1, <- no initializer
    Value2,
    Value3
}

Zalecenia

public enum ValueType
{
    Value1 = 0,
    Value2,
    Value3
}

Wyliczenia kolejności dla odpowiedniego rozszerzenia

Krytyczne jest to, że jeśli wyliczenie prawdopodobnie zostanie rozszerzone w przyszłości, aby uporządkować wartości domyślne w górnej części wyliczenia, gwarantuje to, że indeksy wyliczenia nie mają wpływu na nowe dodatki.

Zakazy

public enum SDKType
{
    WindowsMR,
    OpenVR,
    OpenXR,
    None, <- default value not at start
    Other <- anonymous value left to end of enum
}

Zalecenia

/// <summary>
/// The SDKType lists the VR SDKs that are supported by the MRTK
/// Initially, this lists proposed SDKs, not all may be implemented at this time (please see ReleaseNotes for more details)
/// </summary>
public enum SDKType
{
    /// <summary>
    /// No specified type or Standalone / non-VR type
    /// </summary>
    None = 0,
    /// <summary>
    /// Undefined SDK.
    /// </summary>
    Other,
    /// <summary>
    /// The Windows 10 Mixed reality SDK provided by the Universal Windows Platform (UWP), for Immersive MR headsets and HoloLens.
    /// </summary>
    WindowsMR,
    /// <summary>
    /// The OpenVR platform provided by Unity (does not support the downloadable SteamVR SDK).
    /// </summary>
    OpenVR,
    /// <summary>
    /// The OpenXR platform. SDK to be determined once released.
    /// </summary>
    OpenXR
}

Przejrzyj użycie wyliczenia dla pól bitowych

Jeśli istnieje możliwość, aby wyliczenie wymagało wielu stanów jako wartości, np. Ręka = Lewa & Prawa. Następnie wyliczenie musi być poprawnie ozdobione za pomocą funkcji BitFlags, aby umożliwić poprawne jej użycie

Plik Handedness.cs ma konkretną implementację tego pliku

Zakazy

public enum Handedness
{
    None,
    Left,
    Right
}

Zalecenia

[Flags]
public enum Handedness
{
    None = 0 << 0,
    Left = 1 << 0,
    Right = 1 << 1,
    Both = Left | Right
}

Trwale zakodowane ścieżki plików

Podczas generowania ścieżek plików ciągów, a w szczególności pisania ścieżek ciągów zakodowanych w kodzie, wykonaj następujące czynności:

  1. Używaj interfejsów API języka C#Path, jeśli jest to możliwe, na przykład Path.Combine lub Path.GetFullPath.
  2. Użyj / lub Path.DirectorySeparatorChar zamiast \ lub \\.

Te kroki zapewniają, że rozwiązanie MRTK działa zarówno w systemach z systemami Windows, jak i Unix.

Zakazy

private const string FilePath = "MyPath\\to\\a\\file.txt";
private const string OtherFilePath = "MyPath\to\a\file.txt";

string filePath = myVarRootPath + myRelativePath;

Zalecenia

private const string FilePath = "MyPath/to/a/file.txt";
private const string OtherFilePath = "folder{Path.DirectorySeparatorChar}file.txt";

string filePath = Path.Combine(myVarRootPath,myRelativePath);

// Path.GetFullPath() will return the full length path of provided with correct system directory separators
string cleanedFilePath = Path.GetFullPath(unknownSourceFilePath);

Najlepsze rozwiązania, w tym zalecenia dotyczące aparatu Unity

Niektóre platformy docelowe tego projektu wymagają uwzględnienia wydajności. Mając to na uwadze, zawsze należy zachować ostrożność podczas przydzielania pamięci w często nazywanym kodem w ciasnych pętlach aktualizacji lub algorytmach.

Hermetyzacja

Zawsze używaj pól prywatnych i właściwości publicznych, jeśli dostęp do pola jest potrzebny poza klasą lub strukturą. Pamiętaj, aby współlokować pole prywatne i właściwość publiczną. Ułatwia to błyskawiczne sprawdzenie, co powoduje powrót właściwości i że pole można modyfikować za pomocą skryptu.

Uwaga

Jedynym wyjątkiem jest to, że dla struktur danych, które wymagają serializacji pól przez JsonUtilityklasę , gdzie klasa danych jest wymagana, aby wszystkie pola publiczne serializacji działały.

Zakazy

private float myValue1;
private float myValue2;

public float MyValue1
{
    get{ return myValue1; }
    set{ myValue1 = value }
}

public float MyValue2
{
    get{ return myValue2; }
    set{ myValue2 = value }
}

Zalecenia

// Enable field to be configurable in the editor and available externally to other scripts (field is correctly serialized in Unity)
[SerializeField]
[ToolTip("If using a tooltip, the text should match the public property's summary documentation, if appropriate.")]
private float myValue; // <- Notice we co-located the backing field above our corresponding property.

/// <summary>
/// If using a tooltip, the text should match the public property's summary documentation, if appropriate.
/// </summary>
public float MyValue
{
    get => myValue;
    set => myValue = value;
}

/// <summary>
/// Getter/Setters not wrapping a value directly should contain documentation comments just as public functions would
/// </summary>
public float AbsMyValue
{
    get
    {
        if (MyValue < 0)
        {
            return -MyValue;
        }

        return MyValue
    }
}

Buforuj wartości i serializuj je w scenie/prefab, gdy jest to możliwe

Mając na uwadze urządzenie HoloLens, najlepiej zoptymalizować odwołania do wydajności i pamięci podręcznej w scenie lub prefab w celu ograniczenia alokacji pamięci środowiska uruchomieniowego.

Zakazy

void Update()
{
    gameObject.GetComponent<Renderer>().Foo(Bar);
}

Zalecenia

[SerializeField] // To enable setting the reference in the inspector.
private Renderer myRenderer;

private void Awake()
{
    // If you didn't set it in the inspector, then we cache it on awake.
    if (myRenderer == null)
    {
        myRenderer = gameObject.GetComponent<Renderer>();
    }
}

private void Update()
{
    myRenderer.Foo(Bar);
}

Odwołania do pamięci podręcznej do materiałów nie są wywoływane za każdym razem.

Aparat Unity utworzy nowy materiał za każdym razem, gdy używasz pliku ".material", co spowoduje wyciek pamięci, jeśli nie zostanie prawidłowo oczyszczony.

Zakazy

public class MyClass
{
    void Update()
    {
        Material myMaterial = GetComponent<Renderer>().material;
        myMaterial.SetColor("_Color", Color.White);
    }
}

Zalecenia

// Private references for use inside the class only
public class MyClass
{
    private Material cachedMaterial;

    private void Awake()
    {
        cachedMaterial = GetComponent<Renderer>().material;
    }

    void Update()
    {
        cachedMaterial.SetColor("_Color", Color.White);
    }

    private void OnDestroy()
    {
        Destroy(cachedMaterial);
    }
}

Uwaga

Alternatywnie należy użyć właściwości "SharedMaterial" aparatu Unity, która nie tworzy nowego materiału za każdym razem, gdy się odwołuje.

Korzystanie z kompilacji zależnej od platformy w celu zapewnienia, że zestaw narzędzi nie przerwie kompilacji na innej platformie

  • Użyj WINDOWS_UWP polecenia , aby używać interfejsów API specyficznych dla platformy UWP, innych niż Unity. Uniemożliwi to uruchamianie ich w edytorze lub na nieobsługiwanych platformach. Jest to równoważne UNITY_WSA && !UNITY_EDITOR i powinno być używane na rzecz.
  • Służy UNITY_WSA do używania interfejsów API aparatu Unity specyficznych dla platformy UWP, takich jak UnityEngine.XR.WSA przestrzeń nazw. Spowoduje to uruchomienie w edytorze, gdy platforma jest ustawiona na platformę UWP, a także w wbudowanych aplikacjach platformy UWP.

Ten wykres może pomóc w podjęciu decyzji #if o użyciu, w zależności od przypadków użycia i oczekiwanych ustawień kompilacji.

Platforma UWP IL2CPP Platforma UWP .NET Edytor
UNITY_EDITOR Fałsz Fałsz Prawda
UNITY_WSA Prawda Prawda Prawda
WINDOWS_UWP Prawda Prawda Fałsz
UNITY_WSA && !UNITY_EDITOR Prawda Prawda Fałsz
ENABLE_WINMD_SUPPORT Prawda Prawda Fałsz
NETFX_CORE Fałsz Prawda Fałsz

Preferuj datę/godzinę.UtcNow nad wartością DateTime.Now

DataTime.UtcNow jest szybsza niż DateTime.Now. W poprzednich badaniach wydajności ustaliliśmy, że użycie funkcji DateTime.Now dodaje znaczne obciążenie, szczególnie w przypadku użycia w pętli Update(). Inni dotknęły tego samego problemu.

Wolisz używać wartości DateTime.UtcNow, chyba że w rzeczywistości potrzebujesz zlokalizowanych godzin (uzasadniony powód może być tym, że chcesz pokazać bieżącą godzinę w strefie czasowej użytkownika). Jeśli masz do czynienia z czasem względnym (tj. różnicą między ostatniej aktualizacji a teraz), najlepiej użyć funkcji DateTime.UtcNow, aby uniknąć narzutów na konwersje strefy czasowej.

Konwencje kodowania programu PowerShell

Podzestaw bazy kodu MRTK używa programu PowerShell do infrastruktury potoku oraz różnych skryptów i narzędzi. Nowy kod programu PowerShell powinien być zgodny ze stylem PoshCode.

Zobacz też

Konwencje kodowania języka C# z witryny MSDN