Sdílet prostřednictvím


Pokyny pro kódování – MRTK2

Tento dokument popisuje principy kódování a konvence, které je třeba dodržovat při přispívání do MRTK.


Filozofie

Buďte struční a snažte se o jednoduchost.

Nejjednodušší řešení je často to nejlepší. To je nadřazený cíl těchto pokynů a měl by být cílem všech aktivit kódování. Součástí jednoduchosti je stručné a konzistentní s existujícím kódem. Snažte se, aby váš kód byl jednoduchý.

Čtenáři by se měli setkat pouze s artefakty, které poskytují užitečné informace. Například komentáře, které přehodnocuje to, co je zřejmé, neposkytují žádné další informace a zvyšují poměr šumu k signálu.

Udržujte logiku kódu jednoduchou. Všimněte si, že se nejedná o tvrzení o použití nejmenšího počtu řádků, minimalizaci velikosti názvů identifikátorů nebo stylu závorek, ale o snížení počtu konceptů a maximalizaci viditelnosti těchto prvků prostřednictvím známých vzorů.

Vytváření konzistentního a čitelného kódu

Čitelnost kódu koreluje s nízkou mírou vad. Snažte se vytvořit kód, který je snadno čitelný. Snažte se vytvořit kód, který má jednoduchou logiku a znovu použije existující komponenty, protože to také pomůže zajistit správnost.

Všechny podrobnosti kódu, který vytvoříte, jsou důležité, od nejzákladnějších podrobností správnosti až po konzistentní styl a formátování. Udržujte styl kódování konzistentní s tím, co už existuje, i když neodpovídá vašim preferencím. Tím se zvýší čitelnost celého základu kódu.

Podpora konfigurace komponent v editoru i za běhu

MRTK podporuje různorodou sadu uživatelů – lidí, kteří dávají přednost konfiguraci komponent v editoru Unity a načítání prefab, a lidí, kteří potřebují vytvářet instance a konfigurovat objekty za běhu.

Veškerý váš kód by měl fungovat tak, že přidá komponentu do objektu GameObject v uložené scéně a vytvoří instanci této komponenty v kódu. Testy by měly obsahovat testovací případ pro vytváření instancí prefabů i vytváření instancí a konfiguraci komponenty za běhu.

Play-in-editor je vaše první a primární cílová platforma

Play-In-Editor je nejrychlejší způsob iterace v Unity. Díky možnosti rychlé iterace můžou naši zákazníci rychleji vyvíjet řešení a zkoušet další nápady. Jinými slovy, maximální rychlost iterace umožňuje našim zákazníkům dosáhnout více.

Zajistěte, aby všechno fungovalo v editoru a pak to fungovalo na jakékoli jiné platformě. Pokračujte v práci v editoru. Do play-in-editoru je snadné přidat novou platformu. Je velmi obtížné spustit funkci Play-In-Editor, pokud vaše aplikace funguje jenom na zařízení.

Opatrně přidávat nová veřejná pole, vlastnosti, metody a serializovaná privátní pole

Pokaždé, když přidáte veřejnou metodu, pole nebo vlastnost, stane se součástí veřejné plochy rozhraní API MRTK. Soukromá pole označená [SerializeField] také zpřístupňují pole editoru a jsou součástí veřejné plochy rozhraní API. Jiní uživatelé můžou tuto veřejnou metodu použít, nakonfigurovat vlastní předfaby s veřejným polem a převzít na něm závislost.

Noví veřejní členové by měli být pečlivě prozkoumáni. Všechna veřejná pole budou muset být v budoucnu zachována. Nezapomeňte, že pokud se typ veřejného pole (nebo serializovaného soukromého pole) změní nebo se odebere z MonoBehaviour, může to narušit ostatní uživatele. Pole bude nejprve nutné pro vydání zastaralá a kód pro migraci změn pro uživatele, kteří převzali závislosti, bude potřeba zadat kód.

Stanovení priority psaní testů

MRTK je komunitní projekt, který upravila různorodá škála přispěvatelů. Tito přispěvatelé nemusí znát podrobnosti o opravě nebo funkci chyby a omylem vaši funkci naruší. MRTK před dokončením každé žádosti o přijetí změn spouští testy kontinuální integrace. Změny, které přerušují testy, nelze vrátit se změnami. Testy jsou proto nejlepším způsobem, jak zajistit, aby vaši funkci neporušovali jiní uživatelé.

Když chybu opravíte, napište test, abyste měli jistotu, že v budoucnu nedojde k poklesu. Pokud přidáváte funkci, napište testy, které ověřují, že funkce funguje. To se vyžaduje pro všechny funkce uživatelského prostředí s výjimkou experimentálních funkcí.

Konvence kódování jazyka C#

Hlavičky informací o licencích skriptů

Všichni zaměstnanci Microsoftu, kteří přispívají do nových souborů, by měli na začátek všech nových souborů přidat následující standardní hlavičku licence, přesně tak, jak je znázorněno níže:

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

Záhlaví souhrnu funkcí nebo metod

Všechny veřejné třídy, struktury, výčty, funkce, vlastnosti a pole zasílaná do SADY MRTK by měly být popsány jako jejich účel a použití, přesně tak, jak je znázorněno níže:

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

Tím se zajistí správné vygenerování a šíření dokumentace pro všechny třídy, metody a vlastnosti.

Všechny soubory skriptu odeslané bez správných souhrnných značek budou odmítnuty.

Pravidla oboru názvů MRTK

Sada Mixed Reality Toolkit používá model oboru názvů založený na funkcích, kde všechny základní obory názvů začínají na Microsoft.MixedReality.Toolkit. Obecně platí, že v oborech názvů nemusíte zadávat vrstvu sady nástrojů (např. Core, Providers, Services).

Aktuálně definované obory názvů jsou:

  • 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

Pro obory názvů s velkým množstvím typů je přijatelné vytvořit omezený počet dílčích oborů názvů, které by pomohly při použití oborů.

Vynechání oboru názvů pro rozhraní, třídu nebo datový typ způsobí zablokování změny.

Přidání nových skriptů MonoBehaviour

Při přidávání nových skriptů MonoBehaviour s žádostí o přijetí změn se ujistěte, že AddComponentMenu je atribut použitý na všechny příslušné soubory. Tím zajistíte, že komponenta bude snadno zjistitelná v editoru pod tlačítkem Přidat komponentu . Příznak atributu není nutný, pokud se komponenta nemůže zobrazit v editoru, jako je abstraktní třída.

V následujícím příkladu by měl být balíček vyplněn umístěním balíčku komponenty. Pokud umístíte položku do složky MRTK/SDK , balíček bude SDK.

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

Přidání nových skriptů inspektoru Unity

Obecně se snažte vyhnout vytváření vlastních skriptů inspektoru pro komponenty MRTK. Přidává další režii a správu základu kódu, které by mohl modul Unity zpracovat.

Pokud je potřeba třída inspektoru, zkuste použít unity DrawDefaultInspector(). Tím se opět zjednodušuje třída inspektoru a velká část práce je na Unity.

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

Pokud je ve třídě inspektoru vyžadováno vlastní vykreslování, zkuste použít SerializedProperty a EditorGUILayout.PropertyField. Tím zajistíte, že Unity správně zpracuje vykreslování vnořených prefab a upravených hodnot.

Pokud EditorGUILayout.PropertyField není možné použít kvůli požadavku ve vlastní logice, ujistěte se, že je veškeré použití zabalené kolem objektu EditorGUI.PropertyScope. Tím zajistíte, že Unity správně vykreslí inspektor pro vnořené prefaby a upravené hodnoty s danou vlastností.

Dále se pokuste vyzdobit třídu vlastního inspektoru CanEditMultipleObjectspomocí . Tato značka zajišťuje, že více objektů s touto komponentou ve scéně může být vybráno a upraveno společně. Všechny nové třídy inspektoru by měly otestovat, že jejich kód funguje v této situaci ve scéně.

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

Přidání nových objektů ScriptableObjects

Při přidávání nových skriptů ScriptableObject se ujistěte, že CreateAssetMenu atribut je použit pro všechny příslušné soubory. Tím zajistíte, že komponenta bude snadno zjistitelná v editoru prostřednictvím nabídek pro vytváření prostředků. Příznak atributu není nutný, pokud se komponenta nemůže zobrazit v editoru, jako je abstraktní třída.

V následujícím příkladu by měla být podsložka vyplněna podsložkou MRTK, pokud je k dispozici. Pokud umístíte položku do složky MRTK/Providers , balíček bude Poskytovatelé. Pokud umístíte položku do složky MRTK/Core , nastavte ji na Profily.

V následujícím příkladu myNewService | MyNewProvider by měl být vyplněn názvem vaší nové třídy, pokud je k dispozici. Pokud umístíte položku do složky MixedRealityToolkit , nechejte tento řetězec mimo.

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

protokolování

Při přidávání nových funkcí nebo aktualizaci stávajících funkcí zvažte přidání protokolů DebugUtilities.LogVerbose do zajímavého kódu, který může být užitečný pro budoucí ladění. Tady je kompromis mezi přidáním protokolování a přidaným šumem a nedostatečným protokolováním (což ztěžuje diagnostiku).

Zajímavý příklad, kdy je protokolování užitečné (spolu se zajímavou datovou částí):

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

Tento typ protokolování může pomoct zachytit problémy, jako https://github.com/microsoft/MixedRealityToolkit-Unity/issues/8016jsou , které byly způsobeny událostmi zjištěného neshodného zdroje a ztráty zdroje.

Vyhněte se přidávání protokolů pro data a události, ke kterým dochází v každém rámci – v ideálním případě by protokolování mělo zahrnovat "zajímavé" události řízené odlišnými uživatelskými vstupy (tj. "kliknutím" uživatele a sadou změn a událostí, které pocházejí z toho, které jsou zajímavé pro protokolování). Průběžný stav "uživatel stále drží gesto" protokolovaný v každém snímku není zajímavý a zahltí protokoly.

Všimněte si, že toto podrobné protokolování není ve výchozím nastavení zapnuté (musí být povolené v nastavení diagnostického systému).

Mezery vs. karty

Při přispívání do tohoto projektu používejte místo tabulátorů 4 mezery.

Mezery

Nepřidávejte další mezery mezi hranaté závorky a závorky:

Chybný postup

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

Správný postup

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

Zásady vytváření názvů

Vždy používejte PascalCase pro vlastnosti. Použijte camelCase pro většinu polí s výjimkou polí PascalCase pro static readonly a const . Jedinou výjimkou jsou datové struktury, které vyžadují serializaci polí pomocí JsonUtility.

Chybný postup

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

Správný postup

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

Modifikátory přístupu

Vždy deklarujte modifikátor přístupu pro všechna pole, vlastnosti a metody.

  • Všechny metody rozhraní Unity API by měly být private ve výchozím nastavení, pokud je nepotřebujete přepsat v odvozené třídě. V tomto případě protected by měl být použit.

  • Pole by měla být privatevždy , s vlastnostmi public nebo protected .

  • Pokud je to možné, používejte členy a automatické vlastnostis výrazy.

Chybný postup

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

Správný postup

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

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

Použití závorek

Vždy používejte složené závorky za každým blokem příkazů a umístěte je na další řádek.

Chybný postup

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

Chybný postup

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

Správný postup

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

Veřejné třídy, struktury a výčty by měly být všechny ve svých vlastních souborech.

Pokud může být třída, struktura nebo výčet soukromé, je v pořádku, aby byly zahrnuty do stejného souboru. Tím se vyhnete problémům s kompilacemi v Unity a zajistíte, že dojde k správné abstrakci kódu. Zároveň se tím omezí konflikty a změny způsobující chybu, když se kód potřebuje změnit.

Chybný postup

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

Správný postup

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

Správný postup

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

Inicializace výčtů

Aby se zajistilo, že jsou všechny výčty správně inicializovány od 0, .NET vám poskytne přehlednou zkratku pro automatickou inicializaci výčtu pouhým přidáním první (počáteční) hodnoty. (např. Hodnota 1 = 0 Zbývající hodnoty nejsou povinné)

Chybný postup

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

Správný postup

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

Pořadí výčtů pro příslušné rozšíření

Je důležité, aby pokud je pravděpodobné, že se výčet v budoucnu rozšíří, aby bylo možné uspořádat výchozí hodnoty v horní části výčtu, což zajistí, že indexy výčtu nebudou ovlivněny novými sčítáními.

Chybný postup

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

Správný postup

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

Kontrola použití výčtu pro bitová pole

Pokud je možné, aby výčet vyžadoval více stavů jako hodnotu, např. Odevzdání = Levý & vpravo. Pak musí být výčet správně zdoben BitFlags, aby se mohl správně používat.

Soubor Handedness.cs má konkrétní implementaci

Chybný postup

public enum Handedness
{
    None,
    Left,
    Right
}

Správný postup

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

Pevně zakódované cesty k souborům

Při generování cest k souborům řetězců a zejména při zápisu pevně zakódovaných cest k řetězcům postupujte takto:

  1. Kdykoli je to možné, použijte rozhraní API jazyka Path C#, například Path.Combine nebo Path.GetFullPath.
  2. Místo \ nebo Path.DirectorySeparatorChar \\.

Tyto kroky zajišťují, že sada MRTK funguje v systémech Windows i Unix.

Chybný postup

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

string filePath = myVarRootPath + myRelativePath;

Správný postup

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

Osvědčené postupy, včetně doporučení Unity

Některé cílové platformy tohoto projektu musí brát v úvahu výkon. S ohledem na to buďte vždy opatrní při přidělování paměti v často volaném kódu v úzkých aktualizačních smyček nebo algoritmech.

Zapouzdření

Vždy používejte privátní pole a veřejné vlastnosti, pokud je k poli potřeba přístup mimo třídu nebo strukturu. Nezapomeňte společně najít privátní pole a veřejnou vlastnost. Díky tomu můžete na první pohled jednodušeji vidět, co má vlastnost zpět a že pole je možné upravit pomocí skriptu.

Poznámka

Jedinou výjimkou je u datových struktur, které vyžadují, aby pole byla serializována pomocí JsonUtility, kde datová třída musí mít všechna veřejná pole, aby serializace fungovala.

Chybný postup

private float myValue1;
private float myValue2;

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

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

Správný postup

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

Ukládání hodnot do mezipaměti a jejich serializace ve scéně nebo v prefabu, kdykoli je to možné

S ohledem na HoloLens je nejlepší optimalizovat výkon a ukládat odkazy do mezipaměti ve scéně nebo předem, aby se omezilo přidělení paměti modulu runtime.

Chybný postup

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

Správný postup

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

Ukládat odkazy na materiály, nevolejte pokaždé ".material"

Unity vytvoří nový materiál pokaždé, když použijete .material, což způsobí nevracení paměti, pokud se správně nevyčistí.

Chybný postup

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

Správný postup

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

Poznámka

Případně použijte vlastnost "SharedMaterial" Unity, která nevytvoří nový materiál pokaždé, když se na něj odkazuje.

Použití kompilace závislé na platformě k zajištění, že sada nástrojů nenaruší sestavení na jiné platformě

  • Použijte WINDOWS_UWP k použití rozhraní API specifická pro UPW, která nejsou rozhraní UNITY. To jim zabrání v pokusu o spuštění v editoru nebo na nepodporovaných platformách. To odpovídá UNITY_WSA && !UNITY_EDITOR a mělo by se použít ve prospěch.
  • Slouží UNITY_WSA k použití rozhraní Unity API specifických pro UPW, jako UnityEngine.XR.WSA je například obor názvů. To se spustí v Editoru, když je platforma nastavená na UPW, a také v předdefinovaných aplikacích pro UPW.

Tento graf vám může pomoct při rozhodování, který #if použít, v závislosti na vašich případech použití a očekávaném nastavení sestavení.

Platforma UPW IL2CPP UPW .NET Editor
UNITY_EDITOR Nepravda Nepravda Ano
UNITY_WSA Ano Ano Ano
WINDOWS_UWP Ano Ano Nepravda
UNITY_WSA && !UNITY_EDITOR Ano Ano Nepravda
ENABLE_WINMD_SUPPORT Ano Ano Nepravda
NETFX_CORE Nepravda Ano Ne

Preferovat DateTime.UtcNow před DateTime.Now

DateTime.UtcNow je rychlejší než DateTime.Now. V předchozích šetřeních výkonu jsme zjistili, že používání funkce DateTime.Now zvyšuje významnou režii, zejména při použití ve smyčce Update(). Ostatní se chytli ke stejnému problému.

Raději použijte DateTime.UtcNow, pokud skutečně nepotřebujete lokalizované časy (legitimním důvodem může být zobrazení aktuálního času v časovém pásmu uživatele). Pokud pracujete s relativními časy (tj. rozdíl mezi některými posledními aktualizacemi a teď), je nejlepší použít DateTime.UtcNow, abyste se vyhnuli režii souvisejícím s převody časových pásem.

Konvence kódování PowerShellu

Podmnožina základu kódu MRTK používá PowerShell pro infrastrukturu kanálu a různé skripty a nástroje. Nový kód PowerShellu by měl být ve stylu PoshCode.

Viz také

Konvence kódování C# z MSDN