20 votes

Existe-t-il un modèle C# pour les membres de classe fortement typés avec des méthodes set/get externes ?

J'ai la structure suivante et j'aimerais trouver une solution qui permette de bénéficier des deux classes suivantes. La première classe utilise des chaînes et des membres fortement typés :

public class UserSessionData
{
    private string Get(string key)
    {
        throw new NotImplementedException("TODO: Get from external source");
    }
    private void Set(string key, string value)
    {
        throw new NotImplementedException("TODO: Set in external source");
    }

    public string CustomerNumber {
        get { return Get("CustomerNumber"); }
        set { Set("CustomerNumber", value); }
    }
    public string FirstName {
        get { return Get("FirstName"); }
        set { Set("FirstName", value); }
    }
    public string LastName {
        get { return Get("LastName"); }
        set { Set("LastName", value); }
    }

    // ... a couple of hundreds of these
}

Je peux imaginer une alternative qui serait une Get y Set avec une méthode enum paramètre. Voici la deuxième classe :

public class UserSessionData
{
    public enum What {
        CustomerNumber, FirstName, LastName, // ...
    }

    public string Get (What what) { return MyExternalSource(what); }
    public string Set (What what, string value) { return MyExternalSource(what); }
}

Mais le côté consommateur de la classe 2 n'est pas beau à voir :
UserSessionData.Get(UserSessionData.What.CustomerNumber)
Comparez-la à la première classe : UserSessionData.CustomerNumber

Existe-t-il un moyen fortement typé d'appeler les méthodes Get et Set dans mon exemple de première classe ? En d'autres termes : Comment puis-je bénéficier des avantages des deux classes, à savoir la maintenabilité des membres fortement typés et une syntaxe attrayante ?

34voto

lightbricko Points 1953

.Net 4.5 ou plus récent

Si vous utilisez .Net 4.5 ou une version plus récente, vous pouvez utiliser l'option Attribut CallerMemberName vous pouvez donc l'appeler ainsi :

public string CustomerNumber {
    get { return Get(); }
}

Pour ce faire, modifiez la méthode Get en ajoutant l'attribut au paramètre :

private string Get([CallerMemberName] string key)
{
    ...
}

Avis de performance : Le compilateur insère une chaîne de caractères en tant que paramètre sur le site d'appel, ce qui est rapide.


.Net 4.0 ou antérieur

Si vous utilisez .Net 4.0 ou une version antérieure, vous pouvez toujours utiliser des noms de propriétés fortement typés au lieu de taper des chaînes manuellement, mais vous devez mettre en œuvre une méthode comme ceci pour extraire le nom de la propriété d'un Expression et vous pouvez ensuite l'appeler à l'aide d'une expression :

public string CustomerNumber {
    get { return Get(() => this.CustomerNumber ); }
}

Les fixateurs peuvent être mis en œuvre de la même manière.

Avis de performance : La chaîne est extraite au moment de l'exécution, ce qui est plus lent que l'utilisation de CallerMemberNameAttribute.

8voto

Alex Points 4247

Vous pouvez utiliser un modèle T4 pour générer la classe. Dans le modèle T4, il suffit de nommer toutes les propriétés - vous pourriez également les obtenir par réflexion à partir d'une énumération, mais l'utilisation d'un tableau de chaînes de caractères est plus simple.

Ajouter un nouvel élément -> Modèle de texte

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<# var properties = new string [] {
      "CustomerNumber", // This is where you define the properties
      "FirstName",
      "LastName"
}; #>
class UserSessionData {
<#  
  foreach (string propertyName in properties) 
  { #>
  public string <#= propertyName #>{
    get { return Get("<#= propertyName #>"); }
    set { Set("<#= propertyName #>", value); }
  }
<# } #>
}

Plus d'info @ Génération de code en temps de conception à l'aide de modèles de texte T4

1voto

default.kramer Points 3119

Que diriez-vous d'une énumération avec quelques méthodes d'extension, comme ceci :

// usage:
[TestMethod]
public void example()
{
    UserSessionData.CustomerNumber.Set("cust num");
    Assert.AreEqual("cust num", UserSessionData.CustomerNumber.Get());
}

// implementation:
public enum UserSessionData
{
    CustomerNumber,
    FirstName,
}

public static class UserSessionDataHelper
{
    private static Dictionary<string, string> values = new Dictionary<string, string>();

    private static string GetName(this UserSessionData field)
    {
        return Enum.GetName(typeof(UserSessionData), field);
    }

    public static string Get(this UserSessionData field)
    {
        return values[field.GetName()];
    }

    public static void Set(this UserSessionData field, string value)
    {
        values[field.GetName()] = value;
    }
}

0voto

Gusdor Points 5872

Ce modèle permet de coupler librement les clés de ressources. Une table de hachage qui accepte n'importe quel type de clé, à des fins d'extensibilité. On voit souvent cela avec les messages système dans les conteneurs IoC.

D'après mon expérience, ce modèle offre une grande flexibilité en ce qui concerne le coût de la documentation requise. Envisagez de résoudre le problème par la convention plutôt que par la mise en œuvre. J'essaie de m'en tenir aux valeurs énumérées dans la mesure du possible.

  • Il s'agit de primitives immuables avec des noms forts.
  • Ils peuvent être regroupés dans leur type de parent.
  • Ils peuvent être itérés très simplement si nécessaire.
  • Ils réagissent au remaniement.

0voto

MrDosu Points 2572

Si vous utilisez .NET 4.0 ou une version ultérieure, vous pouvez utiliser Objet dynamique et de remplacer son TryGetMember y TrySetMember pour le faire de manière entièrement dynamique. Cela ne sera cependant pas fortement typé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X