30 votes

c # - Comment obtenir le nom d'une variable tel qu'il a été physiquement tapé dans sa déclaration?

Double Possible:
Trouver le Nom de la Variable passée à une Fonction en C#

La classe ci-dessous contient le champ de la ville.

J'ai besoin de déterminer dynamiquement le nom du champ tel qu'il est tapé dans la déclaration de classe c'est à dire j'ai besoin d'obtenir la chaîne de caractères "ville" à partir d'une instance de l'objet ville.

J'ai essayé de le faire par l'examen de son Type dans DoSomething (), mais ne peut pas le trouver lors de l'examen du contenu de la Type dans le débogueur.

Est-il possible?

public class Person
{
  public string city = "New York";

  public Person()
  {
  }


  public void DoSomething()
  {
    Type t = city.GetType();

    string field_name = t.SomeUnkownFunction();
    //would return the string "city" if it existed!
  }
}

Certaines personnes dans leurs réponses ci-dessous m'ont demandé pourquoi je veux faire ce. Voici pourquoi.

Dans mon monde réel de la situation, il est un attribut personnalisé au-dessus de la ville.

[MyCustomAttribute("param1", "param2", etc)]
public string city = "New York";

J'ai besoin de cet attribut dans un autre code. Pour obtenir de l'attribut, j'ai utiliser la réflexion. Et dans le code de réflexion j'ai besoin de tapez la chaîne de caractères "ville"

MyCustomAttribute attr;
Type t = typeof(Person);

foreach (FieldInfo field in t.GetFields())
{

  if (field.Name == "city")
  {
    //do stuff when we find the field that has the attribute we need
  }

}

Maintenant, ce n'est pas le type de coffre-fort. Si j'ai changé la variable "ville" à "workCity" dans mon champ de la déclaration en Personne cette ligne serait pas, sauf si je savais mettre à jour la chaîne

if (field.Name == "workCity")
//I have to make this change in another file for this to still work, yuk!
{
}

Donc, je suis en train d'essayer de trouver le moyen de passer la chaîne à ce code sans physiquement le taper.

Oui, je pourrais déclarer comme une constante de chaîne en Personne (ou quelque chose comme ça) mais ce serait encore de le taper deux fois.

Ouf! C'était difficile à expliquer!!

Merci

Merci à tous ceux qui ont répondu à cette * beaucoup*. Il m'a envoyé sur une nouvelle voie afin de mieux comprendre les expressions lambda. Et il a créé une nouvelle question.

32voto

Markos Points 830

Je sais que c'est une vieille question, mais je cherche à réaliser le même et google m'a envoyé ici. Après de nombreuses heures, j'ai enfin trouvé un moyen. J'espère que quelqu'un va trouver cela utile.

Il y a plus de moyens pour le faire:

static void Main(string[] args) 
{
  GetName(new { var1 });
  GetName2(() => var1);
  GetName3(() => var1);
}

static string GetName<T>(T item) where T : class 
{
  return typeof(T).GetProperties()[0].Name;
}

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

static string GetName3<T>(Func<T> expr) 
{
  return expr.Target.GetType().Module.ResolveField(BitConverter.ToInt32(expr.Method.GetMethodBody().GetILAsByteArray(), 2)).Name;
}

La première est la plus rapide. Les 2 dernières sont environ 20 fois plus lent que le 1er.

http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html

7voto

Joel Coehoorn Points 190579

city dans ce cas est un exemple de type string. Lorsque vous appelez .GetType() vous du retour de la chaîne type, qui a aucune connaissance de votre ville particulière de l'instance.

Je vais avoir du mal à voir pourquoi vous ne pouvez pas il suffit de taper "ville" dans le code comme une chaîne littérale ici, si c'est ce dont vous avez besoin. Peut-être qu'il serait utile si vous avez partagé ce que vous voulez utiliser cette valeur pour et dans quelles circonstances vous appelez votre DoSomething() fonction.

Pour le moment, ma meilleure supposition est que ce que vous voulez vraiment faire est de refléter l'ensemble de la Person classe pour obtenir une liste des champs de la classe:

public void DoSomething()
{
    MemberInfo[] members = this.GetType().GetMembers();

    // now you can do whatever you want with each of the members,
    // including checking their .Name properties.
}


Ok, basé sur votre modifier j'ai un peu plus pour vous.

Vous pouvez trouver le nom des champs qui sont décorées avec votre attribut au moment de l'exécution, comme ceci:

Type t = typeof(Person);
foreach (MemberInfo member in t.GetMembers()
          .Where(m => 
                m.GetCustomAttributes(typeof(MyCustomAttribute)).Any()  ) )
{
    // "member" is a MemberInfo object for a Peson member that is 
    // decorated with your attribute
}

Vous pouvez également utiliser la liaison de drapeaux dans le premier GetMembers() l'appel de la limiter à seulement champs, si vous le souhaitez.

4voto

shahjapan Points 4043

Oui c'est possible !!!

Essayez ceci ...

   public string DoSomething(object city)
  {
       return city.GetType().GetProperty("Name",typeof(string)).GetValue(city,null);
  }
 

3voto

Abhijeet Patel Points 2116

Vous avez parlé de "c'est à dire j'ai besoin d'obtenir la chaîne de caractères "ville" à partir d'une instance de l'objet ville." Vous êtes à la recherche pour obtenir le nom du champ à partir de la valeur du champ. Par exemple:Si il y a 2 Personne objet de l'un avec les la ville "New York" et l'autre avec de la ville de "Londres", vous êtes à la recherche pour la fonction de retour "en ville". Est-ce que tu veux dire par dynamique?


Avec votre conception actuelle, vous aurez toujours besoin de comparer le nom du champ de la FieldInfo contre une chaîne de caractères. Que faire si vous au lieu de dissocier ce que vous maintenez l'identifiant à utiliser pour des fins de comparaison au cours de la réflexion dans le cadre de l'attribut. Quelque chose comme ceci:

 public enum ReflectionFields
{
    CITY = 0,
    STATE,
    ZIP,    
    COUNTRY

}

[AttributeUsage(AttributeTargets.Field,AllowMultiple=false)]
public class CustomFieldAttr : Attribute
{
    public ReflectionFields Field { get; private set; }
    public string MiscInfo { get; private set; }

    public CustomFieldAttr(ReflectionFields field, string miscInfo)
    {
        Field = field;
        MiscInfo = miscInfo;
    }
}

public class Person
{
    [CustomFieldAttr(ReflectionFields.CITY, "This is the primary city")]
    public string _city = "New York";

    public Person()
    {
    }
    public Person(string city)
    {
        _city = city;
    }

}

public static class AttributeReader<T> where T:class
{
    public static void Read(T t)
    {
        //get all fields which have the "CustomFieldAttribute applied to it"
        var fields = t.GetType().GetFields().Where(f => f.GetCustomAttributes(typeof(CustomFieldAttr), true).Length == 1);

        foreach (var field in fields)
        {
            var attr = field.GetCustomAttributes(typeof(CustomFieldAttr), true).First() as CustomFieldAttr;
            if (attr.Field == ReflectionFields.CITY)
            {
                //You have the field and you know its the City,do whatever processing you need.
                Console.WriteLine(field.Name);
            }
        }            
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        PPerson p1 = new PPerson("NewYork");
        PPerson p2 = new PPerson("London");
        AttributeReader<PPerson>.Read(p1);
        AttributeReader<PPerson>.Read(p2);

}
 }

Vous pouvez maintenant renommer librement _city champ de Personne à quelque chose d'autre et de votre code d'appel fonctionne toujours car le code à l'aide de la réflexion est d'essayer de déterminer le champ à l'aide de la ReflectionFields enum valeur définie dans le cadre de l'initialisation de l'attribut défini sur le domaine.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X