Obtenga propiedades y valores de objetos desconocidos

150

Desde el mundo de PHP, he decidido probar C #. He tenido una búsqueda pero parece que no puedo encontrar la respuesta de cómo hacer el equivalente a esto.

$object = new Object();

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

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

Básicamente tengo una lista de un objeto. El objeto podría ser uno de los tres tipos diferentes y tendrá un conjunto de propiedades públicas. Quiero poder obtener una lista de las propiedades del objeto, recorrerlas y luego escribirlas en un archivo. Estoy pensando que esto tiene algo que ver con la reflexión de C #, pero todo es nuevo para mí.

Cualquier ayuda sería muy apreciada.

m4rc
fuente
9
Como nota al margen: tener objetos de diferentes tipos en una lista (sin una clase base o interfaz común) no es un buen estilo de programación, al menos no en c #.
Albin Sunnanbo

Respuestas:

284

Esto debería hacerlo:

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
fuente
¿De dónde viene PropertyInfo?
Jonathan dos Santos
8
@jonathan System.Reflectionnamespace
Cocowalla
21
Realmente no hay necesidad de crear una lista a partir de una matriz, simplementePropertyInfo[] props = input.GetType().GetProperties();
VladL
2
¿Desea actualizar para la respuesta 2017 usando Newtonsoft.Json.JsonConvert?
Vayne
1
@clone esa es una forma completamente diferente de hacerlo. Debería publicar una respuesta si cree que es un enfoque válido
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
fuente
17

Sí, la reflexión sería el camino a seguir. Primero, obtendría el Typeque representa el tipo (en tiempo de ejecución) de la instancia en la lista. Puede hacer esto llamando al GetTypemétodoObject . Debido a que está en la Objectclase, todos los objetos en .NET pueden llamarlo, ya que todos los tipos se derivan de Object( bueno, técnicamente, no todo , pero eso no es importante aquí).

Una vez que tenga la Typeinstancia, puede llamar al GetPropertiesmétodo para obtener las PropertyInfoinstancias que representan la información de tiempo de ejecución sobre las propiedades en el Type.

Tenga en cuenta que puede usar las sobrecargas de GetPropertiespara ayudar a clasificar qué propiedades recupera.

A partir de ahí, simplemente escribiría la información en un archivo.

Su código anterior, traducido, sería:

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

Tenga en cuenta que si desea información de método o información de campo, deberá llamar a una de las sobrecargas de los métodos GetMethodso GetFieldsrespectivamente.

También tenga en cuenta que una cosa es enumerar los miembros de un archivo, pero no debe usar esta información para conducir la lógica basada en conjuntos de propiedades.

Suponiendo que tiene control sobre las implementaciones de los tipos, debe derivar de una clase base común o implementar una interfaz común y hacer las llamadas en esos (puede usar el operador asu ispara ayudar a determinar con qué clase / interfaz base está trabajando en tiempo de ejecución).

Sin embargo, si no controla estas definiciones de tipo y tiene que manejar la lógica basada en la coincidencia de patrones, entonces está bien.

casperOne
fuente
11

bueno, en C # es similar. Este es uno de los ejemplos más simples (solo para propiedades públicas):

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
fuente
9

Para obtener un valor de propiedad específico del nombre de la propiedad

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

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

para acceder al valor de propiedad de Nombre desde el nombre de cadena de la propiedad

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

Puede usar GetType - GetProperties - Linq Foreach :

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

Solución de una línea usando Linq ...

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

Aquí hay algo que uso para transformar un IEnumerable<T>archivo DataTableque contiene columnas que representan Tlas propiedades de, con una fila para cada elemento en 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;
}

Esto es "algo" demasiado complicado, pero en realidad es bastante bueno para ver cuál es el resultado, ya que puede darle una List<T>de, por ejemplo:

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

Y se le devolverá una DataTable con la estructura:

Marca (cadena)
Año de fabricación (int)

Con una fila por artículo en su List<Car>

Robar
fuente
1

Este ejemplo recorta todas las propiedades de cadena de un objeto.

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
fuente
0

No he encontrado esto para trabajar, digamos objetos de aplicación. Sin embargo, he tenido éxito con

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

string rval = serializer.Serialize(myAppObj);
jcsubmit
fuente
2
No use JavaScriptSerializer si puede evitarlo. Hay muchas muchas razones .
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
fuente
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
fuente
-1

Puedes probar esto:

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

Una vez que cada matriz implementa la interfaz IEnumerable

Pablo Rocha Villagra
fuente