2010-11-24 2 views
2
public class TimeZone 
{ 
    public int Id { get; set; } 
    public string DisplayName{ get; set; } 
} 

Dans une autre classe que j'ai:C# comment obtenir le nom (en chaîne) d'une propriété de classe?

var gmtList = new SelectList(
     repository.GetSystemTimeZones(), 
     "Id", 
     "DisplayName"); 

Note: System.Web.Mvc.SelectList

Je n'aime pas avoir à écrire le nom de la propriété avec "Id" et "DisplayName". Plus tard dans le temps, peut-être que le nom de la propriété changera et le compilateur ne détectera pas cette erreur. C# comment obtenir le nom d'une propriété dans une chaîne?

MISE À JOUR 1

Avec l'aide de Christian Hayter, je peux utiliser:

var tz = new TimeZone(); 
var gmtList = new SelectList(
    repository.GetSystemTimeZones(), 
    NameOf(() => tz.Id), 
    NameOf(() => tz.TranslatedName)); 

OU

var gmtList = new SelectList(
    repository.GetSystemTimeZones(), 
    NameOf(() => new TimeZone().Id), 
    NameOf(() => new TimeZone().TranslatedName)); 

Si quelqu'un a une autre idée sans avoir besoin de créer un nouvel objet. N'hésitez pas à le partager :) merci.

Répondre

13

Vous pouvez créer une méthode utilitaire pour extraire le nom de la propriété d'un arbre d'expression, comme ceci:

string NameOf<T>(Expression<Func<T>> expr) { 
    return ((MemberExpression) expr.Body).Member.Name; 
} 

Ensuite, vous pouvez l'appeler comme ceci:

var gmtList = new SelectList(repository.GetSystemTimeZones(), 
    NameOf(() => tz.Id), 
    NameOf(() => tz.DisplayName)); 

Notez que n'importe quelle instance de la classe fera, puisque vous ne lisez pas la valeur de la propriété, seulement le nom.

+0

Ceci est une excellente solution, mais gardez à l'esprit toute surcharge liée à l'utilisation des arborescences d'expression ainsi que la quantité de refactoring nécessaire quand vient le temps de changer toutes les références. Cela peut même être négligeable, mais il n'y a qu'une seule façon de le savoir! –

+1

Je n'ai pas profilé cela, mais théoriquement le code fonctionne à partir d'un graphe d'objet d'arbre d'expression qui a déjà été construit par le compilateur, donc il devrait être assez rapide pour lire le nom. Si vous voulez lire la * valeur * de l'expression, c'est une toute autre histoire! –

+0

Des tests de performance effectués à ce sujet? Serait-il sage de l'utiliser avec MVVM INotifyPropertyChanged? –

0

(Ce ne sont pas des paramètres BTW, ils sont propriétés.)

Eh bien, une option est d'utiliser les délégués. Par exemple:

public class SelectList<T> 
{ 
    public SelectList(IEnumerable<T> source, 
         Func<T, string> idProjection, 
         Func<T, string> displayProjection) 
    { 
     ... 
    } 
} 

Puis:

var gmtList = new SelectList<TimeZone>(repository.GetSystemTimeZones(), 
             tz => tz.Id, tz => tz.DisplayName); 
+0

Nice option mais le System.Web.Mvc.SelectList 'ne peut pas être utilisé avec des arguments de type. Donc, je ne peux pas utiliser cette solution. Merci quand même :) – asdas

+1

@asdas: Si vous aviez dit de quel type il s'agissait, cela vous aurait beaucoup aidé. Vous nous avez donné aucun contexte. –

0

var name = (string) typeof(TimeZone).GetProperty("DisplayName").GetValue(0);

+0

Encore une fois vous écrivez le DisplayName avec des guillemets. Pas ce que je cherche :) Merci quand même. – asdas

+0

Vous pouvez le remplacer par une variable qui obtient sa valeur à partir d'une source de données externe, idiot:) –

0
string id=typeof(TimeZone).GetProperties()[0].Name; 
string displayName=typeof(TimeZone).GetProperties()[1].Name; 


var gmtList = new SelectList(
    repository.GetSystemTimeZones(), 
    id, 
    displayName); 

cela fonctionnera, à moins que l'ordre dans lequel id et displayname déclaré ne change pas. ou bien vous pouvez penser à définir un attribut pour que la propriété fasse la différence entre id et displayname.

+0

Est une solution de travail :) mais pas très pratique et à l'épreuve des balles. Je vous remercie. – asdas

0

Depuis C# 6.0, vous pouvez maintenant utiliser

var gmtList = new SelectList(
    repository.GetSystemTimeZones(), 
    nameof(TimeZone.Id), 
    nameof(TimeZone.DisplayName)); 
Questions connexes