Eigenschaften und Werte von unbekannten Objekten abrufen

150

Aus der Welt von PHP habe ich beschlossen, C # auszuprobieren. Ich hatte eine Suche, kann aber anscheinend keine Antwort darauf finden, wie ich das Äquivalent dazu machen kann.

$object = new Object();

$vars = get_class_vars(get_class($object));

foreach($vars as $var)
{
    doSomething($object->$var);
}

Ich habe im Grunde eine Liste eines Objekts. Das Objekt kann einer von drei verschiedenen Typen sein und verfügt über eine Reihe öffentlicher Eigenschaften. Ich möchte in der Lage sein, eine Liste der Eigenschaften für das Objekt abzurufen, sie zu durchlaufen und sie dann in eine Datei zu schreiben. Ich denke, das hat etwas mit C # -Reflexion zu tun, aber es ist alles neu für mich.

Jede Hilfe wäre sehr dankbar.

m4rc
quelle
9
Als Randnotiz: Objekte unterschiedlichen Typs in einer Liste zu haben (ohne eine gemeinsame Basisklasse oder Schnittstelle) ist kein guter Programmierstil, zumindest nicht in c #.
Albin Sunnanbo

Antworten:

284

Dies sollte es tun:

Type myType = myObject.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());

foreach (PropertyInfo prop in props)
{
    object propValue = prop.GetValue(myObject, null);

    // Do something with propValue
}
Cocowalla
quelle
Woher kommt PropertyInfo?
Jonathan dos Santos
8
@ Jonathan System.ReflectionNamespace
Cocowalla
21
Es ist nicht wirklich notwendig, eine Liste aus einem Array zu erstellen, einfachPropertyInfo[] props = input.GetType().GetProperties();
VladL
2
Möchten Sie für die Antwort 2017 mit aktualisieren Newtonsoft.Json.JsonConvert?
Vayne
1
@clone das ist eine ganz andere Art es zu tun. Sie sollten eine Antwort posten, wenn Sie denken, dass es ein gültiger Ansatz ist
Cocowalla
23
void Test(){
    var obj = new{a="aaa", b="bbb"};

    var val_a = obj.GetValObjDy("a"); //="aaa"
    var val_b = obj.GetValObjDy("b"); //="bbb"
}
//create in a static class
static public object GetValObjDy(this object obj, string propertyName)
{            
     return obj.GetType().GetProperty(propertyName).GetValue(obj, null);
}
Vo Van Khoa
quelle
17

Ja, Reflexion wäre der richtige Weg. Zunächst erhalten Sie die Type, die den Typ (zur Laufzeit) der Instanz in der Liste darstellt. Sie können dies tun, indem Sie die GetTypeMethodeObject aufrufen . Da es sich in der ObjectKlasse befindet, kann es von jedem Objekt in .NET aufgerufen werden, da alle Typen davon abgeleitet sind Object( technisch gesehen nicht alles , aber das ist hier nicht wichtig).

Sobald Sie die TypeInstanz haben, können Sie die GetPropertiesMethode aufrufen , um die PropertyInfoInstanzen abzurufen, die die Laufzeitinformationen zu den Eigenschaften auf der darstellen Type.

Beachten Sie, dass Sie die Überladungen von verwenden können GetProperties, um zu klassifizieren, welche Eigenschaften Sie abrufen.

Von dort aus schreiben Sie die Informationen einfach in eine Datei.

Ihr Code oben, übersetzt, wäre:

// The instance, it can be of any type.
object o = <some object>;

// Get the type.
Type type = o.GetType();

// Get all public instance properties.
// Use the override if you want to classify
// which properties to return.
foreach (PropertyInfo info in type.GetProperties())
{
    // Do something with the property info.
    DoSomething(info);
}

Beachten Sie, dass Sie, wenn Sie Methoden- oder Feldinformationen wünschen, eine der Überladungen der Methoden GetMethodsoder aufrufen müssen GetFields.

Beachten Sie auch, dass es eine Sache ist, die Mitglieder in einer Datei aufzulisten, aber Sie sollten diese Informationen nicht verwenden, um die Logik basierend auf Eigenschaftssätzen zu steuern.

Angenommen, Sie haben die Kontrolle über die Implementierungen der Typen, sollten Sie von einer gemeinsamen Basisklasse ableiten oder eine gemeinsame Schnittstelle implementieren und diese aufrufen (Sie können den Operator asoder verwenden is, um zu bestimmen, mit welcher Basisklasse / Schnittstelle Sie arbeiten Laufzeit).

Wenn Sie diese Typdefinitionen jedoch nicht steuern und die Logik basierend auf dem Mustervergleich steuern müssen, ist dies in Ordnung.

casperOne
quelle
11

Nun, in C # ist es ähnlich. Hier ist eines der einfachsten Beispiele (nur für öffentliche Immobilien):

var someObject = new { .../*properties*/... };
var propertyInfos = someObject.GetType().GetProperties();
foreach (PropertyInfo pInfo in PropertyInfos)
{
    string propertyName = pInfo.Name; //gets the name of the property
    doSomething(pInfo.GetValue(someObject,null));
}
AlexanderMP
quelle
9

Um einen bestimmten Eigenschaftswert aus dem Eigenschaftsnamen abzurufen

public class Bike{
public string Name {get;set;}
}

Bike b = new Bike {Name = "MyBike"};

um auf den Eigenschaftswert von Name über den Zeichenfolgennamen der Eigenschaft zuzugreifen

public object GetPropertyValue(string propertyName)
{
//returns value of property Name
return this.GetType().GetProperty(propertyName).GetValue(this, null);
} 
Rajnikant
quelle
3

Sie können GetType - GetProperties - Linq Foreach verwenden :

obj.GetType().GetProperties().ToList().ForEach(p =>{
                                                        //p is each PropertyInfo
                                                        DoSomething(p);
                                                    });
Antonio DB
quelle
3

Einzeilige Lösung mit Linq ...

var obj = new {Property1: 1, Property2: 2};
var property1 = obj.GetType().GetProperties().First(o => o.Name == "Property1").GetValue(obj , null);
Chris Wu
quelle
2

Hier ist etwas, das ich verwende, um ein IEnumerable<T>in ein zu verwandeln DataTable, das Spalten enthält, die Tdie Eigenschaften darstellen, mit einer Zeile für jedes Element in IEnumerable:

public static DataTable ToDataTable<T>(IEnumerable<T> items)
{
    var table = CreateDataTableForPropertiesOfType<T>();
    PropertyInfo[] piT = typeof(T).GetProperties();
    foreach (var item in items)
    {
        var dr = table.NewRow();
        for (int property = 0; property < table.Columns.Count; property++)
        {
            if (piT[property].CanRead)
            {
                var value = piT[property].GetValue(item, null);
                if (piT[property].PropertyType.IsGenericType)
                {
                    if (value == null)
                    {
                        dr[property] = DBNull.Value;
                    }
                    else
                    {
                        dr[property] = piT[property].GetValue(item, null);
                    }
                }
                else
                {
                    dr[property] = piT[property].GetValue(item, null);
                }
            }
        }
        table.Rows.Add(dr);
    }
    return table;
}

public static DataTable CreateDataTableForPropertiesOfType<T>()
{
    DataTable dt = new DataTable();
    PropertyInfo[] piT = typeof(T).GetProperties();
    foreach (PropertyInfo pi in piT)
    {
        Type propertyType = null;
        if (pi.PropertyType.IsGenericType)
        {
            propertyType = pi.PropertyType.GetGenericArguments()[0];
        }
        else
        {
            propertyType = pi.PropertyType;
        }
        DataColumn dc = new DataColumn(pi.Name, propertyType);

        if (pi.CanRead)
        {
            dt.Columns.Add(dc);
        }
    }
    return dt;
}

Dies ist "etwas" überkompliziert, aber es ist eigentlich ziemlich gut, um zu sehen, was das Ergebnis ist, wie Sie es List<T>zum Beispiel nennen können:

public class Car
{
    string Make { get; set; }
    int YearOfManufacture {get; set; }
}

Und Sie erhalten eine DataTable mit der folgenden Struktur:

Make (string)
YearOfManufacture (int)

Mit einer Zeile pro Artikel in Ihrem List<Car>

rauben
quelle
1

In diesem Beispiel werden alle Zeichenfolgeneigenschaften eines Objekts gekürzt.

public static void TrimModelProperties(Type type, object obj)
{
    var propertyInfoArray = type.GetProperties(
                                    BindingFlags.Public | 
                                    BindingFlags.Instance);
    foreach (var propertyInfo in propertyInfoArray)
    {
        var propValue = propertyInfo.GetValue(obj, null);
        if (propValue == null) 
            continue;
        if (propValue.GetType().Name == "String")
            propertyInfo.SetValue(
                             obj, 
                             ((string)propValue).Trim(), 
                             null);
    }
}
Brian Paske
quelle
0

Ich habe nicht gefunden, dass dies funktioniert, sagen wir Anwendungsobjekte. Ich habe jedoch Erfolg gehabt mit

var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();

string rval = serializer.Serialize(myAppObj);
jcsubmit
quelle
2
Verwenden Sie JavaScriptSerializer nicht, wenn Sie dies vermeiden können. Es gibt sehr viele Gründe .
Nuno André
0
public Dictionary<string, string> ToDictionary(object obj)
{
    Dictionary<string, string> dictionary = new Dictionary<string, string>();

    Type objectType = obj.GetType();
    IList<PropertyInfo> props = new List<PropertyInfo>(objectType.GetProperties());

    foreach (PropertyInfo prop in props)
    {
        object propValue = prop.GetValue(obj, null);
        dictionary.Add(prop.Name, propValue.ToString());
    }

    return dictionary;
}
Ivan Porta
quelle
0
    /// get set value field in object to object new (two object  field like ) 

    public static void SetValueObjectToObject (object sourceObj , object resultObj)
    {
        IList<PropertyInfo> props = new List<PropertyInfo>(sourceObj.GetType().GetProperties());
        foreach (PropertyInfo prop in props)
        {
            try
            {
                //get value in sourceObj
                object propValue = prop.GetValue(sourceObj, null);
                //set value in resultObj
                PropertyInfo propResult = resultObj.GetType().GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance);
                if (propResult != null && propResult.CanWrite)
                {
                    propResult.SetValue(resultObj, propValue, null);
                }
            }
            catch (Exception ex)
            {  
                // do something with Ex
            }
        }
    }
namsdp
quelle
-1

Sie können dies versuchen:

string[] arr = ((IEnumerable)obj).Cast<object>()
                                 .Select(x => x.ToString())
                                 .ToArray();

Sobald jedes Array die IEnumerable-Schnittstelle implementiert

Pablo Rocha Villagra
quelle