Codierungsrichtlinien — MRTK2

In diesem Dokument werden Codierungsprinzipien und Konventionen beschrieben, die beim Beitrag zu MRTK befolgt werden.


Philosophie

Seien Sie präzise und bemühen Sie sich um Einfachheit

Die einfachste Lösung ist oft die beste. Dies ist ein überschreibendes Ziel dieser Richtlinien und sollte das Ziel aller Codierungsaktivitäten sein. Ein Teil des einfachen Seins ist präzise und konsistent mit vorhandenem Code. Versuchen Sie, Ihren Code einfach zu halten.

Leser sollten nur auf Artefakte stoßen, die nützliche Informationen bereitstellen. Kommentare, die beispielsweise die offensichtlichen Angaben enthalten, bieten keine zusätzlichen Informationen und erhöhen das Rauschen zum Signalverhältnis.

Codelogik einfach halten. Beachten Sie, dass dies keine Anweisung zur Verwendung der kleinsten Anzahl von Zeilen ist, die Größe von Bezeichnernamen oder geschweiften Stilen zu minimieren, sondern die Anzahl der Konzepte zu verringern und die Sichtbarkeit dieser durch vertraute Muster zu maximieren.

Konsistenten, lesbaren Code erzeugen

Die Codelesbarkeit ist mit niedrigen Fehlerraten korreliert. Bemühen Sie sich, Code zu erstellen, der einfach zu lesen ist. Versuchen Sie, Code zu erstellen, der einfache Logik enthält und vorhandene Komponenten erneut verwendet, da sie auch die Richtigkeit gewährleistet.

Alle Details des Codes, den Sie erstellen, sind von den grundlegenden Details der Korrektheit bis hin zu konsistenter Formatvorlage und Formatierung wichtig. Halten Sie Ihren Codierungsstil konsistent mit dem, was bereits vorhanden ist, auch wenn sie nicht mit Ihrer Einstellung übereinstimmt. Dadurch wird die Lesbarkeit der gesamten Codebasis erhöht.

Unterstützung beim Konfigurieren von Komponenten sowohl im Editor als auch zur Laufzeit

MRTK unterstützt eine Vielzahl von Benutzern – Personen, die komponenten im Unity-Editor konfigurieren und Prefabs laden möchten, und Personen, die Objekte zur Laufzeit instanziieren und konfigurieren müssen.

All Your code should work by BOTH add a component to a GameObject in a saved scene, and by instantiating that component in code. Tests sollten sowohl zum Instanziieren von Prefabs als auch zum Instanziieren der Komponente zur Laufzeit einen Testfall enthalten.

Play-in-Editor ist Ihre erste und primäre Zielplattform

Play-In-Editor ist die schnellste Möglichkeit, in Unity zu durchlaufen. Die Bereitstellung von Möglichkeiten für unsere Kunden, schnell zu iterieren, ermöglicht es ihnen, beide Lösungen schneller zu entwickeln und weitere Ideen auszuprobieren. Mit anderen Worten, die Maximierung der Geschwindigkeit der Iteration ermöglicht unseren Kunden, mehr zu erreichen.

Machen Sie alles im Editor, und machen Sie es dann für jede andere Plattform. Arbeiten Sie weiterhin im Editor. Es ist einfach, eine neue Plattform zum Play-In-Editor hinzuzufügen. Es ist sehr schwierig, Play-In-Editor zu verwenden, wenn Ihre App nur auf einem Gerät funktioniert.

Hinzufügen neuer öffentlicher Felder, Eigenschaften, Methoden und serialisierter privater Felder mit Sorgfalt

Jedes Mal, wenn Sie eine öffentliche Methode, ein Feld, eine Eigenschaft hinzufügen, wird sie Teil der öffentlichen API-Oberfläche von MRTK. Private Felder, die mit [SerializeField] auch Feldern für den Editor gekennzeichnet sind und Teil der öffentlichen API-Oberfläche sind. Andere Personen können diese öffentliche Methode verwenden, benutzerdefinierte Präfabs mit Ihrem öffentlichen Feld konfigurieren und eine Abhängigkeit davon übernehmen.

Neue öffentliche Mitglieder sollten sorgfältig geprüft werden. Alle öffentlichen Felder müssen künftig beibehalten werden. Denken Sie daran, dass sich der Typ eines öffentlichen Felds (oder serialisiertes privates Feld) ändert oder aus einem MonoBehaviour entfernt wird, das andere Personen unterbrechen könnte. Das Feld muss zuerst für eine Version veraltet sein, und Code zum Migrieren von Änderungen für Personen, die Abhängigkeiten übernommen haben, muss bereitgestellt werden.

Priorisieren von Schreibtests

MRTK ist ein Communityprojekt, das von verschiedenen Mitwirkenden geändert wird. Diese Mitwirkenden kennen möglicherweise nicht die Details Ihrer Fehlerkorrektur/Funktion, und brechen Sie versehentlich Ihr Feature auf. MRTK führt kontinuierliche Integrationstests aus, bevor jede Pullanforderung abgeschlossen wird. Änderungen, die Tests unterbrechen, können nicht eingecheckt werden. Daher sind Tests die beste Methode, um sicherzustellen, dass andere Personen Ihr Feature nicht unterbrechen.

Wenn Sie einen Fehler beheben, schreiben Sie einen Test, um sicherzustellen, dass er in Zukunft nicht zurückfällt. Wenn Sie ein Feature hinzufügen, schreiben Sie Tests, die überprüfen, ob Das Feature funktioniert. Dies ist für alle UX-Features erforderlich, außer experimentelle Features.

C#-Codierungskonventionen

Skriptheader mit Lizenzinformationen

Alle Microsoft-Mitarbeiter, die neue Dateien mitwirken, sollten oben in allen neuen Dateien den folgenden Standardlizenzheader hinzufügen, genau wie unten dargestellt:

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

Funktions- / Methodenzusammenfassungskopfzeilen

Alle öffentlichen Klassen, Strukturen, Enumerationen, Funktionen, Eigenschaften, Felder, die in MRTK gepostet werden, sollten als Zweck und Verwendung beschrieben werden, genau wie unten dargestellt:

/// <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;
}

Dadurch wird sichergestellt, dass die Dokumentation für alle Klassen, Methoden und Eigenschaften ordnungsgemäß generiert und verbreitet wird.

Alle ohne ordnungsgemäße Zusammenfassung übermittelten Skriptdateien werden abgelehnt.

MRTK-Namespaceregeln

Das Mixed Reality Toolkit verwendet ein featurebasiertes Namespacemodell, bei dem alle grundlegenden Namespaces mit "Microsoft.MixedReality.Toolkit" beginnen. Im Allgemeinen müssen Sie die Toolkitebene (z. B. Core, Providers, Services) in Ihren Namespaces nicht angeben.

Die derzeit definierten Namespaces sind:

  • 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

Für Namespaces mit einer großen Menge von Typen ist es akzeptabel, eine begrenzte Anzahl von Unternamespaces zu erstellen, um die Verwendung zu begrenzen.

Wenn Sie den Namespace für eine Schnittstelle, eine Klasse oder einen Datentyp weglassen, wird Ihre Änderung blockiert.

Hinzufügen neuer MonoBehaviour-Skripts

Stellen Sie beim Hinzufügen neuer MonoBehaviour-Skripts mit einer Pullanforderung sicher, dass das AddComponentMenu Attribut auf alle anwendbaren Dateien angewendet wird. Dadurch wird sichergestellt, dass die Komponente im Editor auf einfache Weise unter der Schaltfläche " Komponente hinzufügen " auffindbar ist. Das Attribut-Flag ist nicht erforderlich, wenn die Komponente im Editor nicht angezeigt werden kann, z. B. eine abstrakte Klasse.

Im folgenden Beispiel sollte das Paket hier mit dem Paketspeicherort der Komponente ausgefüllt werden. Wenn Sie ein Element im MRTK/SDK-Ordner platzieren, ist das Paket SDK.

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

Hinzufügen neuer Unity Inspector-Skripts

Im Allgemeinen versuchen Sie, benutzerdefinierte Inspektorskripts für MRTK-Komponenten zu erstellen. Es fügt zusätzlichen Aufwand und die Verwaltung der Codebasis hinzu, die vom Unity-Modul behandelt werden könnte.

Wenn eine Inspektorklasse erforderlich ist, versuchen Sie, unitys DrawDefaultInspector()zu verwenden. Dies vereinfacht erneut die Inspektorklasse und verlässt einen Großteil der Arbeit an Unity.

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

Wenn ein benutzerdefiniertes Rendering in der Inspektorklasse erforderlich ist, versuchen Sie, es zu verwenden SerializedProperty und EditorGUILayout.PropertyField. Dadurch wird sichergestellt, dass Unity das Rendern geschachtelter Prefabs und geänderter Werte ordnungsgemäß verarbeitet.

Wenn EditorGUILayout.PropertyField aufgrund einer Anforderung in der benutzerdefinierten Logik nicht verwendet werden kann, stellen Sie sicher, dass alle Verwendung um eine .EditorGUI.PropertyScope Dadurch wird sichergestellt, dass Unity den Inspektor korrekt für geschachtelte Prefabs und geänderte Werte mit der angegebenen Eigenschaft rendert.

Versuchen Sie außerdem, die benutzerdefinierte Inspektorklasse mit einer CanEditMultipleObjects. Dieses Tag stellt sicher, dass mehrere Objekte mit dieser Komponente in der Szene zusammen ausgewählt und geändert werden können. Alle neuen Inspektorklassen sollten testen, dass ihr Code in dieser Situation in der Szene funktioniert.

    // 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;
                    });
            }
        }
    }

Hinzufügen neuer ScriptableObjects

Stellen Sie beim Hinzufügen neuer ScriptableObject-Skripts sicher, dass das CreateAssetMenu Attribut auf alle anwendbaren Dateien angewendet wird. Dadurch wird sichergestellt, dass die Komponente im Editor über die Menüs zum Erstellen von Ressourcen leicht auffindbar ist. Das Attribut-Flag ist nicht erforderlich, wenn die Komponente im Editor nicht angezeigt werden kann, z. B. eine abstrakte Klasse.

Im folgenden Beispiel sollte der Unterordner mit dem MRTK-Unterordner ausgefüllt werden, sofern zutreffend. Wenn Sie ein Element im Ordner MRTK/Providers platzieren, ist das Paket Anbieter. Wenn Sie ein Element im MRTK/Core-Ordner platzieren, legen Sie dies auf "Profile" fest.

Im folgenden Beispiel | MyNewProvider sollte ggf. mit dem Namen Ihrer neuen Klasse ausgefüllt werden. Wenn Sie ein Element im Ordner MixedRealityToolkit platzieren, lassen Sie diese Zeichenfolge aus.

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

Protokollierung

Wenn Sie neue Features hinzufügen oder vorhandene Features aktualisieren, sollten Sie DebugUtilities.LogVerbose-Protokolle zu interessantem Code hinzufügen, der für zukünftiges Debuggen nützlich sein kann. Hier gibt es einen Kompromiss zwischen dem Hinzufügen von Protokollierung und dem hinzugefügten Rauschen und nicht genügend Protokollierung (was die Diagnose schwierig macht).

Ein interessantes Beispiel, bei dem die Protokollierung nützlich ist (zusammen mit einer interessanten Nutzlast):

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

Diese Art von Protokollierung kann dazu beitragen, Probleme wie zu https://github.com/microsoft/MixedRealityToolkit-Unity/issues/8016erfassen, die durch falsch erkannte und verlorene Ereignisse der Quelle verursacht wurden.

Vermeiden Sie das Hinzufügen von Protokollen für Daten und Ereignisse, die auf jedem Frame auftreten - idealerweise sollte die Protokollierung "interessante" Ereignisse abdecken, die von unterschiedlichen Benutzereingaben gesteuert werden (z. B. ein "Klick" von einem Benutzer und die Gruppe von Änderungen und Ereignissen, die aus diesem Ereignis stammen, sind interessant zu protokollieren). Der fortlaufende Zustand von "Benutzer hält weiterhin eine Geste" protokolliert, jeder Frame ist nicht interessant und überfordert die Protokolle.

Beachten Sie, dass diese ausführliche Protokollierung standardmäßig nicht aktiviert ist (sie muss in den Diagnosesystemeinstellungen aktiviert werden)

Leerzeichen im Vergleich zu Registerkarten

Bitte achten Sie darauf, 4 Leerzeichen anstelle von Registerkarten zu verwenden, wenn Sie zu diesem Projekt beitragen.

Abstand

Fügen Sie keine zusätzlichen Leerzeichen zwischen eckigen Klammern und Klammern hinzu:

Sie sollten auf keinen Fall

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

Sie sollten

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

Benennungskonventionen

Verwenden Sie PascalCase immer für Eigenschaften. Wird camelCase für die meisten Felder verwendetPascalCase, außer für conststatic readonly Felder. Die einzige Ausnahme sind Datenstrukturen, bei denen die Felder über JsonUtility serialisiert werden müssen.

Sie sollten auf keinen Fall

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

Sie sollten

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

Zugriffsmodifizierer

Deklarieren Sie immer einen Zugriffsmodifizierer für alle Felder, Eigenschaften und Methoden.

  • Alle Unity-API-Methoden sollten standardmäßig als private definiert sein – es sei denn, Sie müssen sie in einer abgeleiteten Klasse überschreiben. In diesem Fall muss protected verwendet werden.

  • Felder sollten immer private privat sein, mit Eigenschaftenzugriff public oder protected.

  • Verwenden von Ausdruckskörpern und automatischen Eigenschaften , sofern möglich

Sie sollten auf keinen Fall

// 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() { }

Sie sollten

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

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

Verwenden von Geschweifte

Verwenden Sie nach jedem Anweisungsblock stets geschweifte Klammern, und platzieren Sie sie in der nächsten Zeile.

Nicht empfohlen

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

Sie sollten auf keinen Fall

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

Sie sollten

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

Öffentliche Klassen, Strukturen und Enumerationen sollten alle in ihren eigenen Dateien enthalten sein.

Wenn die Klasse, die Struktur oder die Enumeration privat gemacht werden kann, ist es in der gleichen Datei in Ordnung. Dadurch werden Kompilierungen mit Unity vermieden und sichergestellt, dass eine ordnungsgemäße Codestraktion auftritt, es reduziert auch Konflikte und Unterbrechungen von Änderungen, wenn Code geändert werden muss.

Sie sollten auf keinen Fall

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

Sie sollten

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

Empfohlen

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;
}

Initialisieren von Enumerationen

Um sicherzustellen, dass alle Enumerationen ordnungsgemäß ab 0 initialisiert werden, erhalten Sie von .NET eine übersichtliche Verknüpfung, um die Enumeration automatisch zu initialisieren, indem Sie einfach den ersten (Starter)-Wert hinzufügen. (z. B. Wert 1 = 0 Verbleibende Werte sind nicht erforderlich)

Sie sollten auf keinen Fall

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

Sie sollten

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

Bestellsummen für die entsprechende Erweiterung

Es ist wichtig, dass, wenn eine Aufzählung in Zukunft verlängert wird, um Standardeinstellungen am Anfang der Aufzählung zu bestellen, stellt dies sicher, dass Enum-Indizes nicht mit neuen Ergänzungen betroffen sind.

Sie sollten auf keinen Fall

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

Sie sollten

/// <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
}

Überprüfen der Aufzählung für Bitfelder

Wenn eine Enumeration mehrere Zustände als Wert erfordert, z. B. Händigkeit = Links & rechts. Anschließend muss die Aufzählung korrekt mit BitFlags versehen werden, damit sie ordnungsgemäß verwendet werden kann.

Die Datei „Handedness.cs“ enthält eine konkrete Implementierung für diesen Fall.

Sie sollten auf keinen Fall

public enum Handedness
{
    None,
    Left,
    Right
}

Sie sollten

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

Hartcodierte Dateipfade

Führen Sie beim Generieren von Zeichenfolgendateipfaden und insbesondere beim Schreiben hartcodierter Zeichenfolgenpfade folgendes aus:

  1. Verwenden Sie C#- Path APIs , wenn möglich, Path.Combine z. B. oder Path.GetFullPath.
  2. Verwenden Sie / oder Path.DirectorySeparatorChar anstelle von \ oder \\.

Diese Schritte stellen sicher, dass MRTK sowohl auf Windows- als auch auf Unix-basierten Systemen funktioniert.

Sie sollten auf keinen Fall

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

string filePath = myVarRootPath + myRelativePath;

Sie sollten

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);

Bewährte Methoden, einschließlich Unity-Empfehlungen

Einige der Zielplattformen dieses Projekts erfordern eine Berücksichtigung der Leistung. Beachten Sie dabei immer, dass Sie beim Zuweisen des Arbeitsspeichers im häufig als Code bezeichneten Code in engen Updateschleifen oder Algorithmen vorsichtig sind.

Kapselung

Verwenden Sie immer private Felder und öffentliche Eigenschaften, wenn von außerhalb der Klasse oder Struktur auf das Feld zugegriffen werden muss. Achten Sie darauf, dass das private Feld und die öffentliche Eigenschaft nebeneinander platziert werden. Dadurch wird es einfacher, auf einen Blick zu sehen, was die Eigenschaft zurückgibt und dass das Feld nach Skript geändert werden kann.

Hinweis

Die einzige Ausnahme sind Datenstrukturen, bei denen die Felder über JsonUtility serialisiert werden müssen, wobei eine Datenklasse zwingend alle öffentlichen Felder enthalten muss, damit die Serialisierung funktioniert.

Sie sollten auf keinen Fall

private float myValue1;
private float myValue2;

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

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

Sie sollten

// 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
    }
}

Cachewerte und serialisieren sie in der Szene/prefab, wenn möglich

Mit Blick auf das HoloLens-System empfiehlt es sich, die Leistung zu optimieren und Verweise in der Szene oder dem Prefab zwischenzuspeichern, um die Speicherbelegung während der Laufzeit zu begrenzen.

Sie sollten auf keinen Fall

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

Sie sollten

[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);
}

Zwischenspeichern von Verweisen auf Materialien, rufen Sie die ".material" nicht jedes Mal auf

Unity erstellt bei jeder Verwendung von „.material“ neues Material, was zu einem Speicherleck führt, wenn keine ordnungsgemäße Bereinigung erfolgt.

Sie sollten auf keinen Fall

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

Sie sollten

// 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);
    }
}

Hinweis

Verwenden Sie alternativ die Unity-Eigenschaft „SharedMaterial“, die nicht bei jedem Verweis neues Material erstellt.

Verwenden einer plattformabhängigen Kompilierung, um Buildfehler durch das Toolkit auf anderen Plattformen zu vermeiden

  • Verwenden Sie WINDOWS_UWP, um UWP-spezifische, Nicht-Unity-APIs zu nutzen. Dadurch wird verhindert, dass sie versuchen, im Editor oder auf nicht unterstützten Plattformen auszuführen. Dies entspricht UNITY_WSA && !UNITY_EDITOR und sollte für sie verwendet werden.
  • Verwenden Sie UNITY_WSA, um UWP-spezifische Unity-APIs zu nutzen, z. B. den UnityEngine.XR.WSA-Namespace. Dies wird im Editor ausgeführt, wenn die Plattform auf UWP festgelegt ist, sowie in integrierten UWP-Apps.

Anhand der folgenden Tabelle können Sie entscheiden, welche #if-Option Sie in Abhängigkeit von Ihren Anwendungsfällen und den erwarteten Buildeinstellungen verwenden sollten.

Plattform UWP IL2CPP UWP .NET Editor
UNITY_EDITOR False False True
UNITY_WSA True True True
WINDOWS_UWP True True False
UNITY_WSA && !UNITY_EDITOR True True False
ENABLE_WINMD_SUPPORT True True False
NETFX_CORE False True False

„DateTime.UtcNow“ gegenüber „DateTime.Now“ bevorzugen

„DateTime.UtcNow“ ist schneller als „DateTime.Now“. In vergangenen Leistungsuntersuchungen haben wir festgestellt, dass die Verwendung von „DateTime.Now“ erheblichen Zusatzaufwand verursacht, insbesondere bei Verwendung in der Update()-Schleife. Dieses Problem ist auch bei anderen Benutzern aufgetreten.

Verwenden Sie lieber „DateTime.UtcNow“ – es sei denn, Sie benötigen tatsächlich die lokalisierten Zeiten (ein legitimer Grund könnte sein, dass Sie die aktuelle Zeit in der Zeitzone des Benutzers anzeigen möchten). Wenn Sie sich mit relativen Zeiten befassen (d. h. das Delta zwischen einigen letzten Aktualisierungen und jetzt), ist es am besten, DateTime.UtcNow zu verwenden, um den Aufwand für die Ausführung von Zeitzonenkonvertierungen zu vermeiden.

PowerShell-Codierungskonventionen

Eine Teilmenge der MRTK-Codebase verwendet PowerShell für Pipelineinfrastruktur und verschiedene Skripts und Dienstprogramme. Neuer PowerShell-Code sollte dem PoshCode-Stil folgen.

Weitere Informationen

C#-Codierungskonventionen aus MSDN