Instructions de codage — MRTK2

Ce document décrit les principes et conventions de codage à suivre lors de la contribution à MRTK.


Philosophie

Soyez concis et efforcez-vous de simplicité

La solution la plus simple est souvent la meilleure. Il s’agit d’un objectif de substitution de ces lignes directrices et doit être l’objectif de toutes les activités de codage. Une partie de la simple consiste à être concis et cohérent avec le code existant. Essayez de simplifier votre code.

Les lecteurs doivent uniquement rencontrer des artefacts qui fournissent des informations utiles. Par exemple, les commentaires qui restèrent ce qui est évident ne fournissent aucune information supplémentaire et augmentent le bruit au rapport signal.

Simplifiez la logique du code. Notez qu’il ne s’agit pas d’une instruction sur l’utilisation du plus petit nombre de lignes, ce qui réduit la taille des noms d’identificateurs ou le style d’accolade, mais sur la réduction du nombre de concepts et l’optimisation de la visibilité de ceux-ci à l’aide de modèles familiers.

Produire du code cohérent et lisible

La lisibilité du code est corrélée avec des taux de défaut faibles. Essayez de créer du code facile à lire. Efforcez-vous de créer du code qui a une logique simple et qui utilise de nouveau des composants existants, car il contribue également à garantir l’exactitude.

Tous les détails du code que vous produisez importent, du détail le plus élémentaire de l’exactitude au style et à la mise en forme cohérents. Gardez votre style de codage cohérent avec ce qui existe déjà, même s’il ne correspond pas à votre préférence. Cela augmente la lisibilité de la base de code globale.

Prise en charge de la configuration des composants à la fois dans l’éditeur et au moment de l’exécution

MRTK prend en charge un ensemble diversifié d’utilisateurs : personnes qui préfèrent configurer des composants dans l’éditeur Unity et charger des préfabriqués, ainsi que des personnes qui doivent instancier et configurer des objets au moment de l’exécution.

Tout votre code doit fonctionner en ajoutant un composant à un GameObject dans une scène enregistrée et en instanciant ce composant dans le code. Les tests doivent inclure un cas de test pour instancier des préfabriqués et instancier, en configurant le composant au moment de l’exécution.

L’éditeur de lecture est votre première plateforme cible principale

Play-In-Editor est le moyen le plus rapide d’itérer dans Unity. Fournir des moyens à nos clients d’itérer rapidement leur permet de développer des solutions plus rapidement et d’essayer plus d’idées. En d’autres termes, l’optimisation de la vitesse d’itération permet à nos clients d’obtenir davantage.

Tout fonctionne dans l’éditeur, puis il fonctionne sur n’importe quelle autre plateforme. Continuez à travailler dans l’éditeur. Il est facile d’ajouter une nouvelle plateforme à Play-In-Editor. Il est très difficile d’utiliser Play-In-Editor si votre application fonctionne uniquement sur un appareil.

Ajouter de nouveaux champs publics, propriétés, méthodes et champs privés sérialisés avec précaution

Chaque fois que vous ajoutez une méthode publique, un champ, une propriété, elle fait partie de la surface d’API publique de MRTK. Les champs privés marqués avec [SerializeField] également des champs exposés à l’éditeur et font partie de la surface d’API publique. D’autres personnes peuvent utiliser cette méthode publique, configurer des préfabriqués personnalisés avec votre champ public et en prendre une dépendance.

De nouveaux membres publics doivent être soigneusement examinés. Tout champ public devra être maintenu à l’avenir. N’oubliez pas que si le type d’un champ public (ou champ privé sérialisé) change ou est supprimé d’un MonoBehaviour, cela peut briser d’autres personnes. Le champ doit d’abord être déconseillé pour une version, et le code permettant de migrer les modifications pour les personnes qui ont pris des dépendances doit être fournie.

Hiérarchiser l’écriture de tests

MRTK est un projet communautaire, modifié par un large éventail de contributeurs. Ces contributeurs peuvent ne pas connaître les détails de votre correctif de bogue/ fonctionnalité, et interrompre accidentellement votre fonctionnalité. MRTK exécute des tests d’intégration continue avant d’effectuer chaque demande de tirage. Les modifications qui arrêtent les tests ne peuvent pas être vérifiées. Par conséquent, les tests constituent la meilleure façon de s’assurer que d’autres personnes ne rompent pas votre fonctionnalité.

Lorsque vous corrigez un bogue, écrivez un test pour vous assurer qu’il ne régresse pas à l’avenir. Si vous ajoutez une fonctionnalité, écrivez des tests qui vérifient que votre fonctionnalité fonctionne. Cela est requis pour toutes les fonctionnalités d’expérience utilisateur, à l’exception des fonctionnalités expérimentales.

Conventions de codage C#

En-têtes d’informations de licence de script

Tous les employés de Microsoft qui contribuent aux nouveaux fichiers doivent ajouter l’en-tête de licence standard suivant en haut de tous les nouveaux fichiers, exactement comme indiqué ci-dessous :

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

En-têtes récapitulatives de fonction/méthode

Toutes les classes publiques, structs, énumérations, fonctions, propriétés, champs publiés dans MRTK doivent être décrits comme étant son objectif et leur utilisation, exactement comme indiqué ci-dessous :

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

Cela garantit que la documentation est correctement générée et diffusée pour toutes les classes, méthodes et propriétés.

Tous les fichiers de script soumis sans les balises de résumé appropriées seront rejetés.

Règles d’espace de noms MRTK

Le kit de ressources Mixed Reality utilise un modèle d’espace de noms basé sur des fonctionnalités, où tous les espaces de noms fondamentaux commencent par « Microsoft.MixedReality.Toolkit ». En général, vous n’avez pas besoin de spécifier la couche de boîte à outils (par exemple, Core, Providers, Services) dans vos espaces de noms.

Les espaces de noms actuellement définis sont les suivants :

  • 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

Pour les espaces de noms avec une grande quantité de types, il est acceptable de créer un nombre limité de sous-espaces de noms pour faciliter l’utilisation de l’étendue.

L’omission de l’espace de noms pour une interface, une classe ou un type de données entraîne le blocage de votre modification.

Ajout de nouveaux scripts MonoBehaviour

Lors de l’ajout de nouveaux scripts MonoBehaviour avec une demande de tirage, vérifiez que l’attribut AddComponentMenu est appliqué à tous les fichiers applicables. Cela garantit que le composant est facilement détectable dans l’éditeur sous le bouton Ajouter un composant . L’indicateur d’attribut n’est pas nécessaire si le composant ne peut pas apparaître dans l’éditeur, tel qu’une classe abstraite.

Dans l’exemple ci-dessous, le package doit être rempli avec l’emplacement du package du composant. Si vous placez un élément dans le dossier MRTK/SDK , le package sera sdk.

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

Ajout de nouveaux scripts d’inspecteur Unity

En général, essayez d’éviter de créer des scripts d’inspecteur personnalisés pour les composants MRTK. Il ajoute une surcharge et une gestion supplémentaires de la base de code qui peuvent être gérées par le moteur Unity.

Si une classe d’inspecteur est nécessaire, essayez d’utiliser DrawDefaultInspector()unity. Cela simplifie à nouveau la classe d’inspecteur et laisse une grande partie du travail à Unity.

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

Si le rendu personnalisé est requis dans la classe inspector, essayez d’utiliser SerializedProperty et EditorGUILayout.PropertyField. Cela garantit que Unity gère correctement le rendu des préfabriqués imbriqués et des valeurs modifiées.

Si EditorGUILayout.PropertyField elle ne peut pas être utilisée en raison d’une exigence dans une logique personnalisée, vérifiez que toute l’utilisation est encapsulée autour d’un EditorGUI.PropertyScope. Cela garantit que Unity restitue correctement l’inspecteur pour les préfabriqués imbriqués et les valeurs modifiées avec la propriété donnée.

En outre, essayez de décorer la classe d’inspecteur personnalisé avec un CanEditMultipleObjects. Cette balise garantit que plusieurs objets avec ce composant de la scène peuvent être sélectionnés et modifiés ensemble. Toutes les nouvelles classes d’inspecteur doivent tester que leur code fonctionne dans cette situation dans la scène.

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

Ajout de nouveaux ScriptableObjects

Lors de l’ajout de nouveaux scripts ScriptableObject, vérifiez que l’attribut CreateAssetMenu est appliqué à tous les fichiers applicables. Cela garantit que le composant est facilement détectable dans l’éditeur via les menus de création de ressources. L’indicateur d’attribut n’est pas nécessaire si le composant ne peut pas apparaître dans l’éditeur, tel qu’une classe abstraite.

Dans l’exemple ci-dessous, le sous-dossier doit être rempli avec le sous-dossier MRTK, le cas échéant. Si vous placez un élément dans le dossier MRTK/Providers , le package est Fournisseur. Si vous placez un élément dans le dossier MRTK/Core , définissez-le sur « Profils ».

Dans l’exemple ci-dessous, le | MyNewService MyNewProvider doit être rempli avec le nom de votre nouvelle classe, le cas échéant. Si vous placez un élément dans le dossier MixedRealityToolkit , conservez cette chaîne.

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

Journalisation

Lorsque vous ajoutez de nouvelles fonctionnalités ou mettez à jour des fonctionnalités existantes, envisagez d’ajouter des journaux DebugUtilities.LogVerbose à du code intéressant qui peut être utile pour le débogage ultérieur. Il y a ici un compromis entre l’ajout de journalisation et le bruit ajouté et pas assez de journalisation (ce qui rend le diagnostic difficile).

Exemple intéressant où la journalisation est utile (avec une charge utile intéressante) :

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

Ce type de journalisation peut aider à intercepter des problèmes tels https://github.com/microsoft/MixedRealityToolkit-Unity/issues/8016que ceux qui ont été provoqués par une source non compatible détectée et des événements perdus à la source.

Évitez d’ajouter des journaux pour les données et les événements qui se produisent sur chaque trame. Dans l’idéal, la journalisation doit couvrir les événements « intéressants » pilotés par des entrées utilisateur distinctes (c’est-à-dire un « clic » par un utilisateur et l’ensemble des modifications et événements qui proviennent de ce qui sont intéressants pour le journal). L’état en cours de « l’utilisateur tient toujours un mouvement » journalisé chaque image n’est pas intéressant et submerge les journaux.

Notez que cette journalisation détaillée n’est pas activée par défaut (elle doit être activée dans les paramètres du système de diagnostic)

Espaces et onglets

Veillez à utiliser 4 espaces au lieu des onglets lors de la contribution à ce projet.

Espacement

N’ajoutez pas d’espaces supplémentaires entre crochets et parenthèses :

À ne pas faire

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

À faire

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

Conventions d’affectation de noms

Toujours utiliser PascalCase pour les propriétés. Utilisez camelCase la plupart des champs, à l’exception des PascalCase champs et const des static readonly champs. La seule exception concerne les structures de données qui requièrent la sérialisation des champs par JsonUtility.

À ne pas faire

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

À faire

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

Modificateurs d’accès

Déclarez toujours un modificateur d’accès pour tous les champs, propriétés et méthodes.

  • Toutes les méthodes de l’API Unity doivent être private par défaut, sauf si vous devez les substituer dans une classe dérivée. Dans ce cas, vous devez utiliser protected.

  • Les champs doivent toujours être private, avec les accesseurs de propriété public ou protected.

  • Utiliser des membres expression-bodied et des propriétés automatiques lorsque cela est possible

À ne pas faire

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

À faire

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

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

Utiliser des accolades

Utilisez toujours des accolades après chaque bloc d’instructions et placez-les à la ligne suivante.

À ne pas faire

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

À ne pas faire

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

À faire

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

Les classes publiques, les structs et les énumérations doivent tous se trouver dans leurs propres fichiers

Si la classe, le struct ou l’énumération peuvent être rendus privés, il est possible d’être inclus dans le même fichier. Cela évite les problèmes de compilation avec Unity et garantit que l’abstraction de code appropriée se produit, elle réduit également les conflits et les changements cassants lorsque le code doit changer.

À ne pas faire

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

À faire

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

Do

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

Initialiser des énumérations

Pour vous assurer que toutes les énumérations sont initialisées correctement à partir de 0, .NET vous donne un raccourci soigné pour initialiser automatiquement l’énumération en ajoutant simplement la première (valeur de démarrage). (Par exemple, la valeur 1 = 0 valeurs restantes n’est pas obligatoire)

À ne pas faire

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

À faire

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

Ordre des énumérations pour l’extension appropriée

Il est essentiel que si une énumération est susceptible d’être étendue à l’avenir, pour classer les valeurs par défaut en haut de l’énumération, cela garantit que les index Enum ne sont pas affectés avec de nouveaux ajouts.

À ne pas faire

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

À faire

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

Examiner l’utilisation de l’énumération pour les champs de bits

S’il existe une possibilité pour une énumération d’exiger plusieurs états en tant que valeur, par exemple La main gauche = Droite gauche & . Ensuite, l’énumération doit être décorée correctement avec BitFlags pour lui permettre d’être utilisé correctement

Le fichier Handedness.cs propose une implémentation concrète pour ce cas

À ne pas faire

public enum Handedness
{
    None,
    Left,
    Right
}

À faire

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

Chemins d’accès aux fichiers codés en dur

Lorsque vous générez des chemins de fichier de chaîne et, en particulier, écrivez des chemins de chaîne codés en dur, procédez comme suit :

  1. Utilisez les API CPath# dans la mesure du possible, telles que Path.Combine ou Path.GetFullPath.
  2. Utilisez / ou Path.DirectorySeparatorChar au lieu de \ ou \\.

Ces étapes garantissent que MRTK fonctionne sur les systèmes Windows et Unix.

À ne pas faire

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

string filePath = myVarRootPath + myRelativePath;

À faire

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

Meilleures pratiques, y compris les recommandations Unity

Certaines des plates-formes cibles de ce projet nécessitent de prendre en compte les performances. Dans cet esprit, soyez toujours prudent lors de l’allocation de mémoire dans le code fréquemment appelé code dans des boucles ou des algorithmes de mise à jour serrés.

Encapsulation

Utilisez toujours des champs privés et des propriétés publiques si l’accès au champ est nécessaire à l’extérieur de la classe ou de la struct. Veillez à colocaliser le champ privé et la propriété publique. Cela permet de voir plus facilement, en un clin d’œil, ce qui revient à la propriété et que le champ est modifiable par script.

Notes

La seule exception concerne les structures de données qui requièrent la sérialisation des champs par JsonUtility, où une classe de données doit posséder tous les champs publics pour que la sérialisation fonctionne.

À ne pas faire

private float myValue1;
private float myValue2;

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

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

À faire

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

Mettre en cache les valeurs et les sérialiser dans la scène/préfabriqué dans la mesure du possible

En gardant HoloLens à l’esprit, il est préférable d’optimiser les performances et les références de cache dans la scène ou le préfabriqué afin de limiter les allocations de mémoire du runtime.

À ne pas faire

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

À faire

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

Mettre en cache les références aux matériaux, n’appelez pas le « .material » chaque fois

Unity crée un nouveau matériau chaque fois que vous utilisez « .material », ce qui entraîne une fuite de mémoire si elle n’est pas nettoyée correctement.

À ne pas faire

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

À faire

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

Notes

Vous pouvez également utiliser la propriété « SharedMaterial » d’Unity, qui ne crée pas de nouveau matériau chaque fois qu’elle est référencée.

Utilisez la compilation dépendante de la plateforme pour vous assurer que Toolkit n’interrompt pas la génération sur une autre plateforme

  • Utilisez afin WINDOWS_UWP d’exécuter des API non Unity spécifiques à UWP. Cela les empêche d’essayer de s’exécuter dans l’éditeur ou sur des plateformes non prises en charge. Cela équivaut et UNITY_WSA && !UNITY_EDITOR devrait être utilisé en faveur de.
  • Utilisez UNITY_WSA pour exécuter des API Unity spécifiques à UWP, par exemple l’espace de noms UnityEngine.XR.WSA. Cela s’exécute dans l’Éditeur lorsque la plateforme est définie sur UWP, ainsi que dans les applications UWP générées.

Ce graphique peut vous aider à choisir ce qui #if doit être utilisé, en fonction de vos cas d’usage et des paramètres de build attendus.

Plateforme UWP IL2CPP UWP .NET Éditeur
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

Préférez DateTime.UtcNow à DateTime.Now

DateTime.UtcNow est plus rapide que DateTime.Now. Dans les enquêtes de performances précédentes, nous avons découvert que l’utilisation de DateTime.Now ajoute une surcharge significative, en particulier dans la boucle Update(). D’autres ont rencontré ce même problème.

Utilisez de préférence DateTime.UtcNow, sauf si vous avez réellement besoin d’heures localisées (vous souhaitiez par exemple afficher l’heure actuelle dans le fuseau horaire de l’utilisateur). Si vous traitez des heures relatives (c’est-à-dire le delta entre une dernière mise à jour et maintenant), il est préférable d’utiliser DateTime.UtcNow pour éviter la surcharge d’effectuer des conversions de fuseau horaire.

Conventions de codage PowerShell

Un sous-ensemble de la base de code MRTK utilise PowerShell pour l’infrastructure de pipeline et divers scripts et utilitaires. Le nouveau code PowerShell doit suivre le style PoshCode.

Voir aussi

Conventions de codage C# à partir de MSDN