2009-09-22 5 views
3

Je trouve récemment beaucoup d'odeurs de code liées au référencement de classes génériques en C#. Mes reproches s'appliquent particulièrement aux classes qui héritent de DependencyObject et contiennent DependencyProperties.Existe-t-il un meilleur moyen de référencer un type?

Le problème de base est que lors de la déclaration d'une propriété de dépendance, on fait généralement référence au type courant qui est également connu sous le nom propriétaire. Cela fonctionne très bien et ne pose généralement pas de problème pour les objets simples non génériques, sauf lorsque l'objet contient plusieurs propriétés de dépendance et que le nom du type doit être recréé à différents endroits (facilité par le refactoring). Visual Studio).

public class MyDependencyObject : DependencyObject 
{ 
    public int MyProperty 
    { 
     get { return (int)GetValue(MyPropertyProperty); } 
     set { SetValue(MyPropertyProperty, value); } 
    } 

    public static readonly DependencyProperty MyPropertyProperty = 
     DependencyProperty.Register("MyProperty", typeof(int), typeof(MyDependencyObject), new UIPropertyMetadata(0)); 
} 

Ce que j'ai été de trouver ces derniers temps cependant est que lorsque l'on combine cette pratique burdonsome explicite auto référencement avec une large utilisation des génériques le code commence vraiment à devenir laid.

public class MyDependencyObject<TypeA, TypeB, TypeC, TypeD> : DependencyObject 
{ 
    public int MyProperty1 
    { 
     get { return (int)GetValue(MyPropertyProperty1); } 
     set { SetValue(MyPropertyProperty1, value); } 
    } 

    public static readonly DependencyProperty MyPropertyProperty1 = 
     DependencyProperty.Register("MyProperty1", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>)); 

    public int MyProperty2 
    { 
     get { return (int)GetValue(MyPropertyProperty2); } 
     set { SetValue(MyPropertyProperty2, value); } 
    } 

    public static readonly DependencyProperty MyPropertyProperty2 = 
     DependencyProperty.Register("MyProperty2", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>)); 

    public int MyProperty3 
    { 
     get { return (int)GetValue(MyPropertyProperty3); } 
     set { SetValue(MyPropertyProperty3, value); } 
    } 

    public static readonly DependencyProperty MyPropertyProperty3 = 
     DependencyProperty.Register("MyProperty3", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>)); 

    public int MyProperty4 
    { 
     get { return (int)GetValue(MyPropertyProperty4); } 
     set { SetValue(MyPropertyProperty4, value); } 
    } 

    public static readonly DependencyProperty MyPropertyProperty4 = 
     DependencyProperty.Register("MyProperty4", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>)); 
} 

Ma question est de savoir si tout le monde est au courant des astuces, des piratages ou des solutions légitimes à réduire le nombre de fois que le nom complet de type avec des paramètres génériques doit être référencé dans des situations telles que celle indiquée ci-dessus. Entièrement divulgué: J'ai soulevé cette question comme un problème sur le site Microsoft .Connect mais ils ont rejeté l'idée d'un self referencing keyword, mais n'ont pas proposé de solution de rechange ou alternative. Mon idée était d'utiliser un mot-clé tel que Propriétaire, OwnerClass, ou ThisType afin de faire référence générique au type dans lequel le mot-clé est utilisé.

Répondre

3

Il y a plusieurs choses que vous pourriez faire pour soulager la douleur. Créez une variable statique qui contient les informations de type pour la classe en cours.

private static readonly Type ThisType = typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>)); 

public int MyProperty1 
{ 
    get { return (int)GetValue(MyPropertyProperty1); } 
    set { SetValue(MyPropertyProperty1, value); } 
} 

public static readonly DependencyProperty MyPropertyProperty1 = 
    DependencyProperty.Register("MyProperty1", typeof(int), ThisType); 

Ensuite, vous pouvez utiliser this astuce pour faire les références à votre getter et setters factoriser sûr.

private static string GetPropertyName<TSource, TResult>(Expression<Func<TSource, TResult>> expression) 
{ 
    if (expression.NodeType == ExpressionType.Lambda && expression.BodyType == ExpressionType.MemberAccess) 
    { 
    PropertyInfo pi = (expression.Body as MemberExpression).Member as PropertyInfo; 
    if (pi != null) 
    { 
     return pi.Name; 
    } 
    } 
    throw new ArgumentException("expression", "Not a property expression."); 
} 

Maintenant votre code aimerait ça.

private static readonly Type ThisType = typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>)); 

public int MyProperty1 
{ 
    get { return (int)GetValue(MyPropertyProperty1); } 
    set { SetValue(MyPropertyProperty1, value); } 
} 

public static readonly DependencyProperty MyPropertyProperty1 = 
    DependencyProperty.Register(GetPropertyName((MyDependencyObject x) => x.MyProperty1), typeof(int), ThisType); 
+0

Excellente idée d'utiliser la variable statique. Deux problèmes encore cependant. 1. Je ne peux pas appliquer des membres statiques à travers toutes mes classes ou au moins les classes qui héritent de la classe de base, donc je vais devoir écrire une variable comme ceci pour chaque DependencyObject que j'écris. 2. Un autre problème est lorsque vous devez vous référer au type en tant que paramètre générique pour une autre déclaration de méthode ou de type. Dans l'ensemble, je pense que votre solution nécessite un code minimal pour produire la variable statique et permet également la flexibilité de la dénomination, ce qui est plutôt agréable. – jpierson

Questions connexes