Ottieni proprietà e valori da un oggetto sconosciuto


150

Dal mondo di PHP ho deciso di provare C #. Ho fatto una ricerca ma non riesco a trovare la risposta su come fare l'equivalente di questo.

$object = new Object();

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

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

Fondamentalmente ho un elenco di un oggetto. L'oggetto potrebbe essere di tre tipi diversi e avrà una serie di proprietà pubbliche. Voglio essere in grado di ottenere un elenco delle proprietà dell'oggetto, scorrere su di esse e quindi scriverle in un file. Sto pensando che questo abbia qualcosa a che fare con la riflessione c # ma è tutto nuovo per me.

Qualsiasi aiuto sarebbe molto apprezzato.


9
Come nota a margine: avere oggetti di tipi diversi in un elenco (senza una classe base o un'interfaccia comuni) non è un buon stile di programmazione, almeno non in c #.
Albin Sunnanbo,

Risposte:


284

Questo dovrebbe farlo:

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
}

da dove viene PropertyInfo?
Jonathan dos Santos,

8
@jonathan System.Reflectionnamespace
Cocowalla

21
Non c'è davvero bisogno di creare un elenco dall'array, semplicementePropertyInfo[] props = input.GetType().GetProperties();
VladL

2
Vuoi aggiornare per la risposta 2017 utilizzando Newtonsoft.Json.JsonConvert?
Vayne,

1
@clone è un modo completamente diverso di farlo. Dovresti pubblicare una risposta se pensi che sia un approccio valido
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);
}

17

Sì, la riflessione sarebbe la strada da percorrere. Innanzitutto, otterrai quello Typeche rappresenta il tipo (in fase di esecuzione) dell'istanza nell'elenco. Puoi farlo chiamando il GetTypemetodoObject . Poiché è nella Objectclasse, è richiamabile da ogni oggetto in .NET, poiché tutti i tipi derivano Object( beh, tecnicamente, non tutto , ma non è importante qui).

Una volta ottenuta l' Typeistanza, è possibile chiamare il GetPropertiesmetodo per ottenere le PropertyInfoistanze che rappresentano le informazioni di runtime sulle proprietà sul Type.

Nota, è possibile utilizzare i sovraccarichi di GetPropertiesper aiutare a classificare cui proprietà si recupera.

Da lì, dovresti semplicemente scrivere le informazioni in un file.

Il tuo codice sopra, tradotto, sarebbe:

// 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);
}

Nota che se vuoi informazioni sul metodo o sul campo, dovresti chiamare rispettivamente uno dei sovraccarichi del metodo GetMethodso GetFields.

Inoltre, è una cosa elencare i membri in un file, ma non si dovrebbero usare queste informazioni per guidare la logica in base ai set di proprietà.

Supponendo che tu abbia il controllo sulle implementazioni dei tipi, dovresti derivare da una classe base comune o implementare un'interfaccia comune ed effettuare chiamate su quelle (puoi usare l' operatore aso isper aiutare a determinare con quale classe base / interfaccia stai lavorando con runtime).

Tuttavia, se non controlli queste definizioni di tipo e devi guidare la logica in base alla corrispondenza dei modelli, allora va bene.


11

bene, in C # è simile. Ecco uno degli esempi più semplici (solo per proprietà pubbliche):

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

9

Per ottenere un valore di proprietà specifico dal nome della proprietà

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

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

per accedere al valore della proprietà di Nome dal nome stringa della proprietà

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

3

Puoi usare GetType - GetProperties - Linq Foreach :

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

3

Soluzione a una linea che utilizza Linq ...

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

2

Ecco qualcosa che uso per trasformare un IEnumerable<T>in un DataTableche contiene colonne che rappresentano Tle proprietà, con una riga per ogni elemento 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;
}

Questo è "piuttosto" complicato, ma in realtà è abbastanza buono per vedere quale sia il risultato, come puoi dargli un List<T>esempio, ad esempio:

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

E ti verrà restituito un DataTable con la struttura:

Make (string)
YearOfManufacture (int)

Con una riga per articolo nel tuo List<Car>


1

In questo esempio vengono tagliate tutte le proprietà della stringa di un oggetto.

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

0

Non ho trovato questo su cui lavorare, diciamo Oggetti applicazione. Ho comunque avuto successo con

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

string rval = serializer.Serialize(myAppObj);

2
Non usare JavaScriptSerializer se puoi evitarlo. Ci sono molte ragioni .
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;
}

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

-1

Puoi provare questo:

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

Una volta che ogni array implementa l'interfaccia IEnumerable

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.