Il doit être un événement assez courant pour modifier le nom d'une propriété et attendre que la fonctionnalité Renommer dans Visual Studio prenne en charge tous les changements de nom nécessaires, à l'exception du nom de propriété de l'événement PropertyChanged de INotifyPropertyChanged. Existe-t-il un meilleur moyen de le faire typer fortement de sorte que vous n'avez pas besoin de se souvenir de le renommer manuellement?Existe-t-il une méthode fortement typée pour faire des événements PropertyChanged en C#?
Répondre
Modifier: nameof
est arrivé dans C# 6. Yay!
Il n'y a pas nameof
/infoof
etc; c'est beaucoup discuté, mais c'est ce que c'est.
Il existe un moyen de le faire en utilisant des expressions lambda dans .NET 3.5 (et en analysant l'arbre d'expression), mais en réalité cela ne vaut pas la surcharge. Pour l'instant, je m'en tiendrai aux cordes (et aux tests unitaires si vous êtes déterminé à ne pas le casser).
using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;
class Program : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
static void Main() {
var p = new Program();
p.PropertyChanged += (s, a) => Console.WriteLine(a.PropertyName);
p.Name = "abc";
}
protected void OnPropertyChanged<T>(Expression<Func<Program, T>> property) {
MemberExpression me = property.Body as MemberExpression;
if (me == null || me.Expression != property.Parameters[0]
|| me.Member.MemberType != MemberTypes.Property) {
throw new InvalidOperationException(
"Now tell me about the property");
}
var handler = PropertyChanged;
if (handler != null) handler(this,
new PropertyChangedEventArgs(me.Member.Name));
}
string name;
public string Name {
get{return name;}
set {
name = value;
OnPropertyChanged(p=>p.Name);
}
}
}
Je vais probablement m'en tenir aux chaînes, mais pour les kicks, pourriez-vous donner un exemple de code court sur la façon d'analyser l'arbre d'expression? – Davy8
Pourquoi utilisez-vous 'Expression
Tout irait bien, mais la version affichée indique clairement que nous recherchons une propriété sur l'instance - pas seulement quelque chose de aléatoire. –
Pas une réponse à votre question, mais si vous faites un clic droit-> Refactor-> Renommer une propriété, il peut également renommer les chaînes correspondantes, y compris toutes les chaînes qui correspondent au nom de votre propriété.
Oui, ça peut être un peu dangereux.
Même renommer dans les commentaires est dangereux. J'ai foiré un tas de documentation XML dans un projet assez volumineux en supposant que cette fonctionnalité limiterait la portée aux commentaires sur/dans l'élément de code qui est renommé. – snarf
Le PropertyChangedEventArgs ne prend qu'un seul constructeur, ce qui nécessite le nom de la propriété sous forme de chaîne. Donc, essentiellement, ne pas utiliser INotifyPropertyChanged signifie qu'à un certain niveau, que ce soit haut ou bas dans votre architecture, vous devrez travailler avec une chaîne et renommer manuellement.
La solution la plus simple est de regarder la trace de la pile et supprimer toute référence completly explicite à la propriété.
public String Name
{
get { return this.name; }
set
{
if (value != this.name)
{
this.RaisePropertyChanging();
this.name = value;
this.RaisePropertyChanged();
}
}
}
private String name = null;
private void RaisePropertyChanged()
{
String propertyName =
new StackTrace().GetFrame(1).GetMethod().Name.SubString(4);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(new PropertyChangedEventArgs(propertyName));
}
}
Le code dérive le nom de la propriété à travers la trace de la pile à partir de la méthode de caling - qui est la méthode de définition de propriété nommée set_<PropertyName>
. Si le compilateur ne suit plus cette convention de dénomination, le code rompt.
L'autre solution consiste à dériver le nom de la propriété d'une expression lambda.
public static String GetPropertyNameFromLambdaExpression<TObject, TProperty>(
Expression<Func<TObject, TProperty>> expression)
{
return ((MemberExpression)expression.Body).Member.Name;
}
Par exemple
GetPropertyNameFromLambdaExpression<String, Int32>(s => s.Length)
retournera "Length
" comme exspected. Une version de production du code exige vraiment des vérifications supplémentaires et une meilleure intégration dans le reste du code. Par exemple, il est possible d'utiliser l'inférence de type pour les arguments génériques.
MISE À JOUR
Et il y a une troisième solution - vous pouvez utiliser MethodBase.GetCurrentMethod()
dans un getter de la propriété ou setter pour obtenir le nom de la méthode setter ou getter.
public String Name
{
get { return this.name; }
set
{
if (value != this.name)
{
String propertyName = MethodBase.GetCurentMethod().Name.SubString(4);
this.RaisePropertyChanging(propertyName);
this.name = value;
this.RaisePropertyChanged(propertyName);
}
}
}
private String name = null;
Cette solution est plus fragile que de simplement définir le nom de la propriété sous forme de chaîne. – Charlie
Cela semble intéressant. Sans vérifier la documentation, je n'arrive pas à comprendre à quoi sert l'appel à SubString. Est-ce que GetMethod(). Name retourne quelque chose d'étrange? –
Une propriété est implémentée par deux méthodes. public MyType MyProperty {get; ensemble; } est implémenté comme public void set_MyProperty (valeur MyType) {} et public MyType get_MyProperty(). Vous devez donc supprimer set_ et get_ du nom de la méthode retournée pour obtenir le nom de la propriété. –
En théorie, vous pouvez utiliser MethodBase.GetCurrentMethod(). Name.Substring (4) à partir du setter de propriété. Malheureusement, la recherche Google révèle que it seems to have a significant performance impact.Deux autres éléments à prendre en compte:
- JIT inlining peut avoir un impact inattendu. (stackoverflow.com/questions/616779/can-i-check-if-the-c-compiler-inlined-a-method-call)
- En théorie, l'appel IL à MethodBase.GetCurrentMethod() pourrait être trivialement remplacé par le JIT à l'exécution avec une instruction ldtoken suivie d'un appel à MethodBase.GetMethodFromHandle(), ce qui serait très rapide. Je suppose que les utilisateurs n'ont tout simplement pas exprimé le besoin de cela. (msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.ldtoken.aspx)
- Complètement mon opinion ici, mais je pense que ce serait bien d'avoir fieldof() et methodof() opérateurs en C#. Je crois que cela améliorerait grandement la fiabilité des outils d'analyse/de refactorisation du code dans les projets qui nécessitent cette capacité.
Vous devriez vérifier ce blog post. Il vous donne la possibilité de le faire:
string propertyName = TypeHelper.GetPropertyName<User>(u => u.LastProjectCode);
PropertyInfo property1 = TypeHelper.GetProperty((SomeClass o) => o.InstanceProperty.Length);
PropertyInfo property2 = TypeHelper.GetProperty(() => SomeClass.StaticProperty.Length);
renomme dans Visual Studio/ReSharper/Refactor Pro devrait fonctionner pour vous alors.
C# 5 semblent avoir une solution. Avec un CallerMemberName
attribute qui peut être utilisé avec les paramètres (One example on the net).
class Employee : INotifyPropertyChanged
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
RaisePropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string caller = "")
{
var temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs(caller));
}
}
}
Wow! Le vôtre semble être le plus cool. – VivekDev
- 1. VB.NET Collection fortement typée
- 2. HandleError avec une vue partielle fortement typée
- 3. Comment améliorer les événements PropertyChanged?
- 4. Comment obtenir un AutoNumber de DataTable AutoIncrementColumn avec une base de données fortement typée en C#?
- 5. Quand n'utiliseriez-vous pas une vue ASP.NET MVC fortement typée?
- 6. Création de Listbox avec une vue fortement typée?
- 7. différence de vue fortement typée (sources MVC vs assemblage)
- 8. Dans .Net, comment convertir une ArrayList en une liste générique fortement typée sans utiliser foreach?
- 9. Linq to Entities Filtrage d'une entité dynamique/fortement typée
- 10. Transférer des événements en C#
- 11. ASP.Net MVC Vue fortement typée avec plusieurs modèles
- 12. C Programmation. Comment faire une méthode pour imprimer une chaîne
- 13. Comment créer une vue MVC fortement typée basée sur une classe Linq2Sql personnalisée
- 14. Mappage de DataSets fortement typés dans une méthode générique FillDataSet en C#?
- 15. Comment récupérer une collection fortement typée qui interroge plusieurs entités avec ActiveRecord de Castle?
- 16. C#: méthode d'enregistrement des événements richtextbox sécurisée par thread?
- 17. Faire une méthode Webservice asynchrone en C#/Winforms
- 18. Comment filtrer une liste fortement typée avec la liste <String> variables
- 19. Comment lier des événements à des ensembles de données fortement typés de types différents?
- 20. Du contrôleur, appliquer le paramètre requis sur une vue MVC fortement typée?
- 21. Notification PropertyChanged pour les propriétés calculées
- 22. Le nom 'Model' n'est pas déclaré dans une vue fortement typée - ASPNET MVC
- 23. Quitter une méthode en C#
- 24. Comment lier une zone de texte à un paramètre Model dans une vue fortement typée dans Asp.Net MVC?
- 25. Gestion des événements filetés (C#)
- 26. Can "Ajouter vue ..." dans MVC.NET ignore une propriété lors de la création d'une vue fortement typée?
- 27. Est-ce une mauvaise pratique de s'abonner à des événements dans une méthode d'extension C#?
- 28. C# pour VB6 événements COM (« objet ou classe ne prend pas en charge l'ensemble des événements »)
- 29. ObservableCollection et Item PropertyChanged
- 30. Comment câbler des événements ToolStripButton par programmation en C#?
(exemple ajouté selon la demande/le commentaire) –
Jetez un oeil à cet article. http://weblogs.asp.net/dwahlin/archive/2009/07/07/validating-properties-in-silverlight-classes.aspx Si vous créez une classe de base qui implémente INotifyPropertyChanged et en dérive, peut-être vous pouvez l'utiliser. –
voir http://stackoverflow.com/questions/1329138/how-to-make-databinding-type-safe-and-support-refactoring/1333874#1333874 pour une manière vérifiée par le compilateur d'implémenter INotifyPropertyChanged. Éviter d'avoir les noms de propriété comme une chaîne magique. –