2009-04-27 8 views
13

Ok. J'ai donc du code qui mappe certains contrôles sur un winForm à certaines propriétés d'un objet, afin de faire certaines choses aux contrôles quand certaines choses arrivent aux données. Tout va bien, fonctionne bien. Pas le problème. La question est, d'ajouter des éléments à la cartographie, j'appelle une fonction qui ressemble à:Extraction de noms de propriété pour la réflexion, avec Intellisense et vérification au moment de la compilation

this.AddMapping(this.myControl,myObject,"myObjectPropertyName"); 

Le problème que je cours en est qu'il est très difficile de dire, au moment de la compilation, la différence entre la ligne ci-dessus et ci-dessous:

this.AddMapping(this.myControl,myObject,"myObjectPropretyName"); 

Depuis le dernier paramètre est une chaîne, il n'y a pas de temps de compilation vérifier ou quelque chose comme ça qui l'application que la chaîne elle-même correspond en fait à un nom de propriété valide sur l'objet donné. En outre, des éléments tels que Refactor et "Find All References" manquent sur ce type de référence, ce qui entraîne une hilarité lorsque le nom de la propriété change lui-même. Donc ce que je me demande, c'est s'il y a un moyen de changer la fonction de sorte que ce que je passe est toujours une chaîne représentant le nom de la propriété d'une certaine façon, mais avec la vérification de la valeur réelle. pourrait le faire avec Expression Trees, mais j'ai lu sur eux et ne semble pas voir la connexion. J'aimerais faire quelque chose comme:

this.AddMapping(this.myControl,myObject,myObject.myObjectPropertyName); 

ou même

this.AddMapping(this.myControl,myObject.myObjectPropertyName); 

serait doux!

Des idées?

+0

Il a fallu 6 ou 7 passages avant que je puisse détecter la différence entre vos deux lignes de code. – jjnguy

+0

Bienvenue dans mon enfer ... maintenant imaginez-le jonché d'acronymes tels que CPCR, CPR, CLI, etc ... – GWLlosa

+0

Depuis longtemps, je souhaite une sorte de VS ajouter qui permettrait d'analyser toutes les chaînes de votre le code et l'orthographe les vérifient. Cela prendrait également en compte l'enveloppe du chameau, et l'orthographe vérifie chaque mot individuellement. Quelqu'un doit écrire ce meunier .... – BFree

Répondre

14

dans 3.5, L'expression est un moyen de spécifier des noms de membres en tant que code; vous pourriez avoir:

public void AddMapping<TObj,TValue>(Control myControl, TObj myObject, 
     Expression<Func<TObj, TValue>> mapping) {...} 

puis d'analyser l'arbre d'expression pour obtenir la valeur. Un peu inefficace, mais pas trop mal.

est ici un exemple de code:

public void AddMapping<TSource, TValue>(
     Control control, 
     TSource source, 
     Expression<Func<TSource, TValue>> mapping) 
    { 
     if (mapping.Body.NodeType != ExpressionType.MemberAccess) 
     { 
      throw new InvalidOperationException(); 
     } 
     MemberExpression me = (MemberExpression)mapping.Body; 
     if (me.Expression != mapping.Parameters[0]) 
     { 
      throw new InvalidOperationException(); 
     } 
     string name = me.Member.Name; 
     // TODO: do something with "control", "source" and "name", 
     // maybe also using "me.Member" 
    } 

appelé avec:

AddMapping(myControl, foo, f => f.Bar); 
1

Vous ne devriez pas être en train de transmettre des littéraux String en tant que noms de propriété. Au lieu de cela, vous devriez utiliser YourClass.PROPERTY_NAME_FOO.

Vous devez déclarer ces chaînes comme des constantes dans votre classe.

public const String PROPERTY_NAME_FOO = "any string, it really doesn't matter"; 
public const String PROPERTY_NAME_BAR = "some other name, it really doesn't matter"; 

Ou bien, vous n'avez pas à vous soucier des chaînes du tout, juste des noms de propriété:

public const int PROPERTY_NAME_FOO = 0; 
public const int PROPERTY_NAME_BAR = 1; //values don't matter, as long as they are unique 

qui arrêterait les chaînes qui ne se réfèrent pas à une propriété valide d'entrer dans les appels de fonction . Intelisense sera en mesure de vous montrer les noms de propriété à l'intérieur de votre classe comme suggestions pour l'auto-complétion.

+0

J'ai pensé à cela, La seule chose qui me dérange, c'est que c'est redondant ... Vous maintenez maintenant les informations de propriété dans 2 endroits séparés (la chaîne const et le nom de la propriété elle-même) qui semble moins qu'optimale. – GWLlosa

+0

Vous n'avez vraiment pas besoin d'utiliser une chaîne. Vous pourriez juste les mapper aux ints ou n'importe quoi. C'est le nom qui est important et le fait que les valeurs sont uniques. – jjnguy

+0

Mais si je ne les mappe pas aux chaînes, comment puis-je éventuellement obtenir une valeur de chaîne? – GWLlosa

2

Pensez à utiliser pour cette lambdas ou même System.Linq.Expressions, avec l'un des:

extern void AddMapping<T,U>(Control control, T target, Func<T,U> mapping); 
extern void AddMapping<T,U>(Control control, T target, Expression<Func<T,U>> mapping); 

Ensuite, appelez avec

this.AddMapping(this.myControl, myObject, (x => x.PropertyName)); 

Utilisez l'argument Expression si vous devez démonter l'arborescence de la syntaxe abstraite lors de l'exécution pour effectuer des opérations de réflexion telles que l'obtention du nom de la propriété sous forme de chaîne; Alternativement, laissez le délégué faire le travail de pêcher les données dont vous avez besoin.

3

Pour faciliter les choses avec l'expression à base de solution lamda, je l'ai écrit comme une méthode d'extension.

public static string GetPropertyName<T>(this object o, Expression<Func<T>> property) 
    { 
     var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo; 
     if (propertyInfo == null) 
      throw new ArgumentException("The lambda expression 'property' should point to a valid Property"); 
     var propertyName = propertyInfo.Name; 
     return propertyName; 
    } 

Appel comme celui-ci

class testclass 
    { 
     public string s { get; set; } 
     public string s2 { get; set; } 
     public int i { get; set; } 

    } 

    [TestMethod] 
    public void TestMethod2() 
    { 
     testclass x = new testclass(); 
     string nameOfPropertyS = this.GetPropertyName(() => x.s); 
     Assert.AreEqual("s", nameOfPropertyS); 

     string nameOfPropertyI = x.GetPropertyName(() => x.i); 
     Assert.AreEqual("i", nameOfPropertyI); 

    } 

Bon, en utilisant comme méthode d'extension est vraiment pour la commodité que vous pouvez en fait appeler la méthode sur une classe pour les propriétés de classe anthères. Je suis sûr que cela pourrait être amélioré.

+0

Je peux voir quelques commentaires relatifs à l'utilisation de la méthode d'extension, la raison pour laquelle je voulais mettre la main sur ceci était pour WPF Binding (mvvm) afin que vous puissiez appeler OnPropertyChanged (this.GetProperty (() => MyProperty); aider à résoudre certains problèmes liés à la sécurité lors de la compilation de cette liaison wpf.Au moins si vous changez le nom de la propriété, vous obtenez un peu de sécurité à la compilation.Vous devez toujours modifier le texte de liaison dans votre xaml si ... –

Questions connexes