2009-02-01 13 views
2

Est-ce que C# a quelque chose comme __getattr__ de Python?Les accesseurs de repli en C#?

J'ai une classe avec beaucoup de propriétés, et ils partagent tous le même code d'accesseur. Je voudrais être capable de supprimer complètement les accesseurs individuels, comme en Python.

Voici ce que mon code ressemble maintenant:

class Foo 
{ 
    protected bool Get(string name, bool def) 
    { 
     try { 
      return client.Get(name); 
     } catch { 
      return def; 
     } 
    } 

    public bool Bar 
    { 
     get { return Get("bar", true); } 
     set { client.Set("bar", value); } 
    } 

    public bool Baz 
    { 
     get { return Get("baz", false); } 
     set { client.Set("baz", value); } 
    } 
} 

Et voici ce que je voudrais:

class Foo 
{ 
    public bool Get(string name) 
    { 
     try { 
      return client.Get(name); 
     } catch { 
      // Look-up default value in hash table and return it 
     } 
    } 

    public void Set(string name, object value) 
    { 
     client.Set(name, value) 
    } 
} 

Est-il possible d'y parvenir en C# sans appeler Get directement?

Merci,

Répondre

2

No. Bien que C# prend en charge la réflexion, il est lu -lyly (pour les assemblages chargés). Cela signifie que vous ne pouvez pas modifier de méthodes, de propriétés ou d'autres métadonnées. Bien que vous pourriez create a dynamic property, l'appeler ne serait pas très pratique - ce serait encore pire que d'utiliser votre méthode Get. En plus d'utiliser un Dictionary<string, object> et un indexeur pour votre classe, vous ne pouvez pas faire grand-chose d'autre. De toute façon, ne fait-il pas mieux un dictionnaire si vous avez autant de propriétés?

Python ne vérifie pas si un attribut existe à la "compilation" (ou au moins au moment du chargement). C# fait. C'est une différence fondamentale entre les deux langues. En Python, vous pouvez le faire:

class my_class: 
    pass 

my_instance = my_class() 
my_instance.my_attr = 1 
print(my_instance.my_attr) 

en C# vous ne seriez pas en mesure de le faire parce que C# vérifie effectivement si le nom my_attr existe au moment de la compilation.

+0

Les propriétés ne sont pas * nombreuses * (environ 20), mais c'est la répétition de code quand même, et je n'aime pas la voir. =) Je veux utiliser des propriétés plutôt qu'un dictionnaire pour la même raison. Les propriétés sont plus belles. Oh, et les clés du client pourraient changer. –

+0

C'est impossible. C# n'a même pas de #define à usage général! – wj32

0

Ce n'est pas la même chose que ce que vous obtenez en Python avec les noms de propriétés dynamiques, mais vous trouverez peut-être utile:

using System; 
using System.Collections.Generic; 

namespace Program 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyList<int> list = new MyList<int>(); 
      // Add a property with setter. 
      list["One"] = 1; 
      // Add a property with getter which takes default value. 
      int two = list["Two", 2]; 
      Console.WriteLine("One={0}", list["One"]); 
      Console.WriteLine("Two={0}/{1}", two, list["Two"]); 
      try 
      { 
       Console.WriteLine("Three={0}", list["Three"]); 
      } 
      catch 
      { 
       Console.WriteLine("Three does not exist."); 
      } 
     } 
     class MyList<T> 
     { 
      Dictionary<string, T> dictionary = new Dictionary<string,T>(); 

      internal T this[string property, T def] 
      { 
       get 
       { 
        T value; 
        if (!dictionary.TryGetValue(property, out value)) 
         dictionary.Add(property, value = def); 
        return value; 
       } 
      } 
      internal T this[string property] 
      { 
       get 
       { 
        return dictionary[property]; 
       } 
       set 
       { 
        dictionary[property] = value; 
       } 
      } 
     } 
    } 
} 
+0

Je ne suis pas sûr de comprendre ce que vous entendez par TryGet (le client est une classe de bibliothèque, donc je ne peux pas changer son comportement), mais les performances ne sont pas très importantes de toute façon. –

+0

Par exemple, Système.Collections.Generic.Dictionary a une méthode TryGetValue qui renvoie true si la clé est déjà présente et false dans le cas contraire. Si la classe que vous utilisez n'a pas cette méthode, alors vous n'avez pas le choix et c'est une bonne chose que la performance n'a pas d'importance. –

+0

OK, j'ai changé ma réponse pour quelque chose que vous pourriez trouver utile (est-ce?). Notez que l'indexeur qui prend une valeur par défaut utilise TryGetValue pour éviter le try/catch. –

1

Je ne suis pas sûr, mais peut-être que les fonctionnalités dynamiques de la version 4.0 vous y aideront. Vous devrez attendre si ...

+0

Oui, ils le feront. Voir http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject%28VS.100%29.aspx – wj32

+0

Hehe, avec votre vote, j'ai maintenant rep 1969. Quelle coïncidence, hein? –

1

Puis-je demander: pourquoi vous ne voulez pas les propriétés individuelles? C'est la façon idiomatique .NET d'exprimer les données associées à un objet.

Personnellement, en supposant que les données ne sont pas rares, je garderais les propriétés et ont la réflexion globale de l'utilisation de la méthode - cela rendra votre code compilé aussi vite que possible:

protected T Get<T>(string name, T @default) 
    { 
     var prop = GetType().GetProperty(name); 
     if(prop == null) return @default; 
     return (T) prop.GetValue(this, null); 
    } 

Bien sûr, si vous ne se soucient pas des propriétés elles-mêmes en cours de définition, alors un indexeur et une recherche (comme le dictionnaire) serait OK. Il y a aussi des choses que vous pourriez faire avec postsharp pour transformer un ensemble de propriétés en un sac de propriétés - mais cela ne vaut probablement pas le coup.

Si vous souhaitez que les propriétés disponibles pour la liaison de données et la détection d'exécution, mais ne peuvent pas les définir lors de la compilation, vous devez examiner les descripteurs de type dynamique; soit ICustomTypeDescriptor ou TypeDescriptionProvider - un peu de travail, mais très polyvalent (laissez-moi savoir si vous voulez plus d'informations).

+0

Je * veux * les propriétés individuelles, je ne veux pas de répétition de code inutile. Comme je l'ai dit en réponse à la réponse de Joe Erickson, la performance n'est pas si importante. –

+0

Donc, en utilisant mon approche de réflexion ci-dessus - ce qui est dupliqué? –