Come si ottiene il nome di una variabile così come è stata digitata fisicamente nella sua dichiarazione?

Possibile duplicato:
Trovare il nome della variabile passato a una funzione in C #

La class qui sotto contiene la città campo.

Ho bisogno di determinare dynamicmente il nome del campo mentre viene digitato nella dichiarazione della class, cioè ho bisogno di ottenere la stringa “città” da un’istanza della città object.

Ho provato a fare questo esaminando il suo tipo in DoSomething () ma non riesco a trovarlo quando si esamina il contenuto del tipo nel debugger.

È ansible?

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! } } 

Alcune persone nelle loro risposte di seguito mi hanno chiesto perché voglio farlo. Ecco perché.

Nella mia situazione del mondo reale, c’è un attributo personalizzato sopra la città.

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

Ho bisogno di questo attributo in un altro codice. Per ottenere l’attributo, uso la riflessione. E nel codice di riflessione ho bisogno di digitare la stringa “città”

 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 } } 

Ora questo non è sicuro. Se avessi cambiato la variabile “city” in “workCity” nella mia dichiarazione di campo in Person questa riga sarebbe fallita a meno che non sapessi di aggiornare la stringa

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

Quindi sto cercando di trovare un modo per passare la stringa a questo codice senza digitarlo fisicamente.

Sì, potrei dichiararlo come costante di una stringa in Persona (o qualcosa del genere), ma lo scriverei ancora due volte.

Accidenti! È stato difficile da spiegare !!

Grazie

Grazie a tutti quelli che hanno risposto a questo * molto *. Mi ha inviato un nuovo percorso per comprendere meglio le espressioni lambda. E ha creato una nuova domanda.

Forse hai bisogno di questo. Funziona bene.

Ho trovato questo qui .

 static void Main(string[] args) { var domain = "matrix"; Check(() => domain); Console.ReadLine(); } static void Check(Expression> expr) { var body = ((MemberExpression)expr.Body); Console.WriteLine("Name is: {0}", body.Member.Name); Console.WriteLine("Value is: {0}", ((FieldInfo)body.Member) .GetValue(((ConstantExpression)body.Expression).Value)); } 

L’output sarà:

 Il nome è: 'dominio'
 Il valore è: 'matrice'

So che questa è una vecchia domanda, ma stavo cercando di ottenere lo stesso e Google mi ha mandato qui. Dopo molte ore ho finalmente trovato un modo. Spero che qualcun altro lo troverà utile.

Ci sono in realtà più modi per realizzare questo:

 static void Main(string[] args) { GetName(new { var1 }); GetName2(() => var1); GetName3(() => var1); } static string GetName(T item) where T : class { return typeof(T).GetProperties()[0].Name; } static string GetName2(Expression> expr) { return ((MemberExpression)expr.Body).Member.Name; } static string GetName3(Func expr) { return expr.Target.GetType().Module.ResolveField(BitConverter.ToInt32(expr.Method.GetMethodBody().GetILAsByteArray(), 2)).Name; } 

Il primo è il più veloce. Gli ultimi 2 sono circa 20 volte più lenti del primo.

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

city in questo caso è un’istanza di tipo string . Quando chiami .GetType() restituisci il tipo di stringa effettivo, che non ha alcuna conoscenza della tua particolare istanza di città.

Sto avendo difficoltà a capire perché non puoi semplicemente digitare “città” nel codice come stringa letterale qui, se è quello che ti serve. Forse sarebbe d’aiuto se tu condividessi ciò che vuoi usare per questo valore e in quali circostanze chiamerai la funzione DoSomething() .

Al momento, la mia ipotesi migliore è che ciò che si vuole veramente fare è riflettere l’intera class Person per ottenere un elenco dei campi in quella class:

 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, in base alla tua modifica ne ho ancora dell’altro.

Puoi trovare il nome dei campi che sono decorati con il tuo attributo in fase di esecuzione come questo:

 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 } 

È inoltre ansible utilizzare i flag di bind nella prima chiamata a GetMembers () per limitarla a soli campi, se lo si desidera.

Hai menzionato “cioè ho bisogno di ottenere la stringa” città “da un’istanza della città object.” Stai cercando di ottenere il nome del campo dal valore del campo. Per esempio: se ci sono 2 oggetti Person con la città “New York” e l’altro con la città “London”, stai cercando la funzione per restituire “city”. È questo che intendi per dynamic?


Con il tuo progetto attuale dovrai sempre confrontare il nome del campo di FieldInfo con una stringa. Che cosa succede se si disaccoppia questo in modo che si tenga l’identificatore da utilizzare per scopi di confronto durante la riflessione come parte dell’attributo. Qualcosa come questo:

  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 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.Read(p1); AttributeReader.Read(p2); } } 

È ora ansible rinominare liberamente il campo _city di Person con qualcos’altro e il codice chiamante continuerà a funzionare poiché il codice che utilizza reflection sta tentando di identificare il campo utilizzando il valore enum di ReflectionFields come parte dell’inizializzazione dell’attributo impostato sul campo.

Si è ansible !!!

Prova questo …

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

Due cose qui.

Numero uno, come ha sottolineato qualcuno sopra, stai ricevendo il Type per string, non per Person. Quindi typeof (Person) .GetMembers () ti porterà la lista dei membri.

Numero due, e ancora più importante, sembra che tu stia fraintendendo lo scopo degli attributi. In generale, gli attributi vengono utilizzati per contrassegnare un membro per l’elaborazione specifica o per aggiungere ulteriori informazioni. Qui stai usando il nome per indicare quale elaborazione vuoi e l’attributo per specificare i parametri, che è un mix di metafore o qualcosa del genere.

La risposta di Abhijeet è più appropriata, contrassegni il campo come un campo cittadino, poi fai quello che ti piace con esso. Dove non sono d’accordo è che userei diverse classi di attributi, piuttosto che un’enumerazione.

Qualcosa di simile a:

  public class MyAttribute : Attribute { } [AttributeUsage(AttributeTargets.Field)] public class MyCityAttribute : MyAttribute { } [AttributeUsage(AttributeTargets.Field] public class MyNameAttribute: MyAttribute { } public class Person { [MyCity] public string city = "New York"; [MyCity] public string workCity = "Chicago"; [MyName] public string fullName = "John Doe"; public Person() { } public void DoSomething() { Type t = typeof(Person); FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (var field in fields) { MyAttribute[] attributes = field.GetCustomAttributes(typeof(MyAttribute)); if (attributes.Count > 0) { if (attributes[0] is MyCityAttribute) { //Dosomething for city break; } if (attributes[0] is MyNameAttribute) { //Dosomething for names break; } } } } } 

Questo ti permetterebbe di usare diversi parametri per MyCity vs MyName che avrebbe più senso nel contesto dell’elaborazione di ciascuno.

Penso che con il tuo commento ‘yuk’ qui sopra, hai colpito l’unghia sulla testa. Che tu debba modificare una costante di stringa se rinomina la tua variabile è un indicatore che stai facendo qualcosa di sbagliato.

 t.GetField("city", BindingFlags.Public | BindingFlags.Instance); 

oppure puoi chiamare GetFields () per ottenere tutti i campi

Devi chiamare get digitare sulla class Person. L’iterazione dei campi della class come nella risposta seguente

Questo non è ansible (penso che sia in realtà, ma invola diversi hack e usando lambda). Se si desidera memorizzare gli attributi di una Person e poter ottenere facilmente il nome dell’attributo, suggerisco di utilizzare un Dictionary dallo spazio System.Collections.Generic nomi System.Collections.Generic .

E puoi sempre rendere pubbliche le proprietà che avvolgono il dizionario.

 public class Person { Dictionary attributes = new Dictionary 

E puoi ottenere un elenco di tutti gli attributi con attributes.Keys . attributes.Keys .

Dai un’occhiata a questo post in quanto sembra simile a quello che stai cercando di fare:

Trovare il nome della variabile passato a una funzione

(in particolare la risposta di Konrad Rudolph) Un altro approccio potrebbe essere semplicemente aggiungere “città” come uno dei parametri dell’attributo e pescare in seguito.

Stai già eseguendo il ciclo attraverso la raccolta di oggetti FieldInfo . Cerca il tuo attributo su quelli e quando trovi il FieldInfo che contiene il tuo attributo, hai quello che vuoi. Quindi chiama .Name su di esso.

system.reflection.fieldinfo.attributes