2010-11-10 18 views
105

Desde el mundo de PHP, he decidido dar C# a go. He tenido una búsqueda pero no puedo encontrar la respuesta de cómo hacer el equivalente a esto.Obtener propiedades y valores del objeto desconocido

$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 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 C# pero es todo nuevo para mí.

Cualquier ayuda sería muy apreciada.

+7

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

Respuesta

205

Esto debe 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 
} 
+0

¿De dónde viene PropertyInfo? – Jonathan

+8

@jonathan 'System.Reflection' namespace – Cocowalla

+12

No hay necesidad de crear una lista de array, simplemente' PropertyInfo [] props = input.GetType(). GetProperties(); ' – VladL

16

Sí, la reflexión sería el camino a seguir. Primero, obtendría el Type que representa el tipo (en tiempo de ejecución) de la instancia en la lista. Puede hacer esto llamando al GetType method on Object. Debido a que está en la clase Object, se puede llamar por cada objeto en .NET, ya que todos los tipos derivan de Object (well, technically, not everything, pero eso no es importante aquí).

Una vez que tenga la instancia Type, puede llamar a la GetProperties method para obtener los PropertyInfo casos que representan el tiempo de ejecución informationa acerca de las propiedades en el Type.

Nota, puede usar las sobrecargas de GetProperties para ayudar a clasificar que propiedades recupera.

A partir de ahí, solo debe escribir 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 sobre el método o la información de campo, que tendría que llamar a la una de las sobrecargas de los métodos GetMethods o GetFields respectivamente.

También tenga en cuenta que una cosa es enumerar a los miembros en un archivo, pero no debe usar para usar esta información para conducir la lógica en función de 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 as o is para ayudar a determinar qué clase base/interfaz con la que está trabajando en tiempo de ejecución).

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

2

Aquí es algo que utilizo para transformar un IEnumerable<T> en un DataTable que contiene columnas que representan T 's propiedades, con una fila para cada elemento de la 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 es en realidad bastante bueno para ver cuál es el resultado, como se puede darle un List<T> de, por ejemplo:

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

Y se le devolvió un DataTable con el st ructure:

Make (cadena)
YearOfManufacture (int)

Con una fila por cada elemento en su List<Car>

7

así, en C# Es similar. Aquí está uno de los ejemplos más simples (sólo para las 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)); 
} 
1

En este ejemplo se 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); 
    } 
} 
6

Para obtener valor de la propiedad específica del nombre de la propiedad

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

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

acceder valor de la propiedad del nombre del nombre de la cadena de la propiedad

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

Puede utilizar getType - GetProperties - LINQ Foreach:

obj.GetType().GetProperties().ToList().ForEach(p =>{ 
                 //p is each PropertyInfo 
                 DoSomething(p); 
                }); 
6
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); 
} 
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); 
0

Puede probar esto:

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

vez cada variedad implementa la interfaz IEnumerable

Cuestiones relacionadas