1210 Stimmen

Abrufen des Eigenschaftswerts aus einer Zeichenkette mittels Reflexion

Ich versuche die Implementierung der Datentransformation mit Reflection 1 Beispiel in meinem Code.

Le site GetSourceValue Funktion hat einen Schalter, der verschiedene Typen vergleicht, aber ich möchte diese Typen und Eigenschaften entfernen und die GetSourceValue den Wert der Eigenschaft mit nur einer einzigen Zeichenkette als Parameter abrufen. Ich möchte eine Klasse und eine Eigenschaft in der Zeichenfolge übergeben und den Wert der Eigenschaft auflösen.

Ist dies möglich?

1 <a href="https://web.archive.org/web/20130815002453/http://msmvps.com/blogs/shahed/archive/2008/07/24/c-reflection-tips-data-transformation-using-reflection.aspx" rel="noreferrer">Webarchiv-Version des ursprünglichen Blogbeitrags</a>

2281voto

Ed S. Punkte 118985
 public static object GetPropValue(object src, string propName)
 {
     return src.GetType().GetProperty(propName).GetValue(src, null);
 }

Natürlich müssen Sie noch die Validierung und andere Dinge hinzufügen, aber das ist das Wesentliche.

44 Stimmen

Schön und einfach! Ich würde es aber generisch machen: public static T GetPropertyValue<T>(object obj, string propName) { return (T)obj.GetType().GetProperty(propName).GetValue(obj, null); }

11 Stimmen

Eine Optimierung kann das Risiko einer Null-Ausnahme wie diese beseitigen: " src.GetType().GetProperty(propName)?.GetValue(src, null); " ;).

27 Stimmen

@shA.t: Ich halte das für eine schlechte Idee. Wie unterscheidet man zwischen einem Nullwert einer vorhandenen Eigenschaft oder gar keiner Eigenschaft? Ich würde lieber sofort wissen, dass ich einen falschen Eigenschaftsnamen eingegeben habe. Dies ist kein Produktionscode, aber eine bessere Verbesserung wäre es, eine spezifischere Ausnahme auszulösen (z.B. Prüfung auf Null bei GetProperty und werfen PropertyNotFoundException oder etwas anderes, wenn null).

260voto

jheddings Punkte 25451

Wie wäre es mit so etwas wie diesem:

public static Object GetPropValue(this Object obj, String name) {
    foreach (String part in name.Split('.')) {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        PropertyInfo info = type.GetProperty(part);
        if (info == null) { return null; }

        obj = info.GetValue(obj, null);
    }
    return obj;
}

public static T GetPropValue<T>(this Object obj, String name) {
    Object retval = GetPropValue(obj, name);
    if (retval == null) { return default(T); }

    // throws InvalidCastException if types are incompatible
    return (T) retval;
}

So können Sie mit einer einzigen Zeichenfolge in die Eigenschaften hinabsteigen, etwa so:

DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");

Sie können diese Methoden entweder als statische Methoden oder als Erweiterungen verwenden.

4 Stimmen

@FredJand Schön, dass Sie darüber gestolpert sind! Es ist immer wieder überraschend, wenn diese alten Beiträge auftauchen. Er war ein wenig vage, also habe ich ein wenig Text hinzugefügt, um ihn zu erklären. Ich bin auch dazu übergegangen, diese als Erweiterungsmethoden zu verwenden und habe ein generisches Formular hinzugefügt, also habe ich es hier hinzugefügt.

0 Stimmen

Warum ist die Null-Wache in der foreach und nicht oben?

5 Stimmen

@Santhos da "obj" im Körper der foreach-Schleife neu definiert wird, wird es bei jeder Iteration überprüft.

120voto

Eduardo Cuomo Punkte 15791

Hinzufügen zu jeder Class :

public class Foo
{
    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }

    public string Bar { get; set; }
}

Dann können Sie als verwenden:

Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];

0 Stimmen

@EduardoCuomo: Ist es möglich, Reflexion mit diesem zu verwenden, so dass Sie nicht wissen müssen, welche Mitglieder die Klasse hat?

0 Stimmen

Ist es möglich, dies zu tun, wenn "Bar" ein Objekt wäre?

0 Stimmen

@big_water der SetValue y GetValue Methoden arbeitet mit Object . Wenn Sie mit einem bestimmten Typ arbeiten müssen, sollten Sie das Ergebnis von GetValue und cast den Wert, um ihn mit SetValue

48voto

Fredou Punkte 19430

Wie wäre es mit der Verwendung des CallByName de la Microsoft.VisualBasic Namensraum ( Microsoft.VisualBasic.dll )? Es verwendet Reflexion, um Eigenschaften, Felder und Methoden von normalen Objekten, COM-Objekten und sogar dynamischen Objekten zu erhalten.

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

und dann

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();

6 Stimmen

Ein interessanter Vorschlag, der bei näherer Betrachtung zeigt, dass er sowohl Felder als auch Eigenschaften und COM-Objekte verarbeiten kann, und es kann sogar dynamische Bindungen korrekt verarbeiten !

0 Stimmen

Ich erhalte eine Fehlermeldung: Öffentliches Mitglied 'MyPropertyName' auf Typ 'MyType' nicht gefunden.

46voto

AlexD Punkte 391

Tolle Antwort von jheddings . Ich würde es gerne verbessern, indem ich die Referenzierung von aggregierten Arrays oder Sammlungen von Objekten erlaube, so dass propertyName sein könnte property1.property2[X].property3 :

    public static object GetPropertyValue(object srcobj, string propertyName)
    {
        if (srcobj == null)
            return null;

        object obj = srcobj;

        // Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
        string[] propertyNameParts = propertyName.Split('.');

        foreach (string propertyNamePart in propertyNameParts)
        {
            if (obj == null)    return null;

            // propertyNamePart could contain reference to specific 
            // element (by index) inside a collection
            if (!propertyNamePart.Contains("["))
            {
                PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart);
                if (pi == null) return null;
                obj = pi.GetValue(obj, null);
            }
            else
            {   // propertyNamePart is areference to specific element 
                // (by index) inside a collection
                // like AggregatedCollection[123]
                //   get collection name and element index
                int indexStart = propertyNamePart.IndexOf("[")+1;
                string collectionPropertyName = propertyNamePart.Substring(0, indexStart-1);
                int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length-indexStart-1));
                //   get collection object
                PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName);
                if (pi == null) return null;
                object unknownCollection = pi.GetValue(obj, null);
                //   try to process the collection as array
                if (unknownCollection.GetType().IsArray)
                {
                    object[] collectionAsArray = unknownCollection as object[];
                    obj = collectionAsArray[collectionElementIndex];
                }
                else
                {
                    //   try to process the collection as IList
                    System.Collections.IList collectionAsList = unknownCollection as System.Collections.IList;
                    if (collectionAsList != null)
                    {
                        obj = collectionAsList[collectionElementIndex];
                    }
                    else
                    {
                        // ??? Unsupported collection type
                    }
                }
            }
        }

        return obj;
    }

0 Stimmen

Was ist mit einer Liste von Listen, auf die mit MasterList[0][1] zugegriffen wird?

0 Stimmen

As Array -> as object[] führt ebenfalls zu einer Nullreferenz-Ausnahme. Was funktioniert für mich (prop nicht effizienteste Methode), ist unknownCollection zu IEnumerable casten und dann ToArray() auf das Ergebnis verwenden. fiddle

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X