Yo estaba haciendo algo como De forma recursiva Obtener Propiedades & Hijo Propiedades De Un Objeto, pero yo quería usar la reflexión de forma recursiva para obtener cada una de las propiedades. Y me dieron el código de De forma recursiva las propiedades de Impresión.

El problema con el código es: no sólo va en la planta de abajo, me pregunto ¿cómo se puede obtener automáticamente todas las propiedades mediante la reflexión? Acabo de hacer el siguiente ejemplo de código del Contenedor:

public class Container
{
public Bottle MyBottle { get; set; }
public List<Address> Addresses { get; set; }
public Container()
{
Address a = new Address();
a.AddressLine1 = "1 Main St";
a.AddressLine2 = "2 Main St";
Addresses = new List<Address>();
Addresses.Add(a);
MyBottle = new Bottle();
MyBottle.BottleName = "Big bottle";
MyBottle.BottageAge = 2;
}
}
public class Bottle
{
public string BottleName { get; set; }
public int BottageAge { get; set; }
}
public class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public List<SpecialFolder> SpecialFolders { get; set; }
public Address()
{
SpecialFolders = new List<SpecialFolder>();
SpecialFolder sf = new SpecialFolder();
sf.TemplateFolder = Environment.SpecialFolder.Templates.ToString();
sf.UserFolder = Environment.SpecialFolder.UserProfile.ToString();
SpecialFolders.Add(sf);
}
}
public class SpecialFolder
{
public string TemplateFolder { get; set; }
public string UserFolder { get; set; }
}

En el método Main:

static void Main(string[] args)
{
Container c = new Container();
PrintProperties(c);
}
public static void PrintProperties(object obj)
{
PrintProperties(obj, 0);
}
public static void PrintProperties(object obj, int indent)
{
if (obj == null) return;
string indentString = new string(' ', indent);
Type objType = obj.GetType();
PropertyInfo[] properties = objType.GetProperties();
foreach (PropertyInfo property in properties)
{
object propValue = property.GetValue(obj, null);
if (property.PropertyType.Assembly == objType.Assembly)
{
Console.WriteLine("{0}{1}:", indentString, property.Name);
PrintProperties(propValue, indent + 2);
}
else
{
Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
}
}
}

Estoy esperando a conseguir:

MyBottle:
BottleName: Big bottle
BottageAge: 2
Addresses:
AddressLine1: 1 Main St
AddressLine2: 2 Main St
SpecialFolders:
TemplateFolder: Templates
UserFolder: UserProfile

El resultado que tengo ahora:

MyBottle:
BottleName: Big bottle
BottageAge: 2
Addresses: System.Collections.Generic.List`1[TreeViewReflectionExample.Address]

Alguien me puede ayudar con el PrintProperties método? Muchas gracias.

InformationsquelleAutor HoKy22 | 2013-12-12

5 Comentarios

  1. 49

    Tienes dos problemas con el código:

    1. debido a la condición if (property.PropertyType.Assembly == objType.Assembly) vas a omitir System.Collections como List<>
    2. no tratar de forma diferente propValue que son colecciones. Por lo tanto, es de impresión List propiedades, y no a sus elementos, propiedades.

    Puede cambiar eso, por ejemplo, en:

    public void PrintProperties(object obj, int indent)
    {    
    if (obj == null) return;
    string indentString = new string(' ', indent);
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();
    foreach (PropertyInfo property in properties)
    {
    object propValue = property.GetValue(obj, null);
    var elems = propValue as IList;
    if (elems != null)
    {
    foreach (var item in elems)
    {
    PrintProperties(item, indent + 3);
    }
    }
    else
    {
    //This will not cut-off System.Collections because of the first check
    if (property.PropertyType.Assembly == objType.Assembly)
    {
    Console.WriteLine("{0}{1}:", indentString, property.Name);
    PrintProperties(propValue, indent + 2);
    }
    else
    {
    Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
    }
    }
    }
    }
    • Exactamente lo que estaba buscando, no solo trabajó para este ejemplo, pero para todos los demás casos, se había
    • Esto fue útil. He hecho una pequeña suma para asegurarse de que la propiedad puede ser leído antes de llamar a GetValue para evitar una excepción en un sólo escritura de propiedad – acaba con «si (la propiedad.CanRead) {…».
    • Un bonito y pequeño bocado de C# 6 azúcar sintáctico: if (propValue is IList elems) trabaja y ahorra una línea.
    • Tengo un System.Reflection.TargetParameterCountException con esta configuración: var person = new Person { Name = "Name", Vorname = "Firstname", Alter = 27, Adresse = new Adresse { Strasse = "Street", Ort = "Place" }, Hobbies = new List<string> { "Tennis", "Salsa", "blub" } };
    • Buen código, pero no de la impresión de la Lista de tipos integrados, correo.g List<int>, también Arrays
    • el ahorro de una línea no es el punto. Por lo que el código de error más seguro es. Cada lanzamiento es en cierto modo el riesgo de que un programador comete un error. Esto hace que sea el tipo de seguro de todo el camino.
    • A menos que usted está abonado por línea de código, concisa beats detallado de cada momento. Ver aquí.
    • Mi punto era que la mayor ventaja de usar este tipo de coincidencia de patrón no es el acortamiento de código, pero evitando los errores humanos. Cada fundición pueden fallar en la teoría. Si la variable es de tipo no acepta valores null, es más seguro.

  2. 13

    Desea controlar los tipos primitivos y cadenas por separado, y un bucle en enumerables en lugar de sólo tomar su método ToString() de valor. Así que su código puede ser actualizado a:

    public void PrintProperties(object obj, int indent)
    {
    if (obj == null) return;
    string indentString = new string(' ', indent);
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();
    foreach (PropertyInfo property in properties)
    {   
    object propValue = property.GetValue(obj, null);
    if(property.PropertyType.IsPrimitive || property.PropertyType == typeof(string))
    Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
    else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
    {
    Console.WriteLine("{0}{1}:", indentString, property.Name);
    IEnumerable enumerable = (IEnumerable)propValue;
    foreach(object child in enumerable)
    PrintProperties(child, indent + 2);
    }
    else 
    {
    Console.WriteLine("{0}{1}:", indentString, property.Name);
    PrintProperties(propValue, indent + 2);
    }
    }
    }
    • Este código funciona muy bien para este ejemplo, cuando he añadido algunos más propiedades y clases, tengo bucle infinito. Yo estaba buscando una manera genérica para obtener todas las propiedades.
    • Después de algunas pequeñas modificaciones de este código funcionó para mí.
  3. 1

    Funciona para todos los casos, excepto propValue es string[]. Usted recibirá la excepción «número de Parámetro no coincide» en línea:
    objeto propValue = propiedad.GetValue(obj, null);

    Para solucionar este problema, puedes utilizar este código con un poco de revisión:

    private void PrintProperties(object obj, int indent)
    {
    if (obj == null) return;
    string indentString = new string(' ', indent);
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();
    foreach (PropertyInfo property in properties)
    {
    object propValue = property.GetValue(obj, null);
    var elems = propValue as IList;
    if ((elems != null) && !(elems is string[]) )
    {
    foreach (var item in elems)
    {
    PrintProperties(item, indent + 3);
    }
    }
    else
    {
    //This will not cut-off System.Collections because of the first check
    if (property.PropertyType.Assembly == objType.Assembly)
    {
    LogToWindow(String.Format("{0}{1}:", indentString, property.Name));
    PrintProperties(propValue, indent + 2);
    }
    else
    {
    if (propValue is string[])
    {
    var str = new StringBuilder();
    foreach (string item in (string[])propValue)
    {
    str.AppendFormat("{0}; ", item);
    }
    propValue = str.ToString();
    str.Clear();
    }
    LogToWindow(String.Format("{0}{1}: {2}", indentString, property.Name, propValue));
    }
    }
    }
    }
  4. 1

    Basado en Konrad Kokosa la respuesta:

    private string ObjectToString(object obj, int indent = 0)
    {
    if (obj is null)
    {
    return "";
    }
    var sb = new StringBuilder();
    string indentString = new string(' ', indent);
    Type objType = obj.GetType();
    foreach (PropertyInfo property in objType.GetProperties())
    {
    object propValue = property.GetValue(obj);
    var elems = propValue as IList;
    if (elems != null)
    {
    foreach (var item in elems)
    {
    sb.Append($"{indentString}- {property.Name}\n");
    sb.Append(ObjectToString(item, indent + 4));
    }
    }
    else if (property.Name != "ExtensionData")
    {
    sb.Append($"{indentString}- {property.Name}={propValue}\n");
    if (property.PropertyType.Assembly == objType.Assembly)
    {
    sb.Append(ObjectToString(propValue, indent + 4));
    }
    }
    }
    return sb.ToString();
    }

    ACTUALIZACIÓN

    Editar el código basado en esta antigua pregunta: TargetParameterCountException cuando se enumeran las propiedades de la cadena

    private string ObjectToString(object obj, int indent = 0)
    {
    var sb = new StringBuilder();
    if (obj != null)
    {
    string indentString = new string(' ', indent);
    if (obj is string)
    {
    sb.Append($"{indentString}- {obj}\n");
    }
    else if (obj is Array)
    {
    var elems = obj as IList;
    sb.Append($"{indentString}- [{elems.Count}] :\n");
    for (int i = 0; i < elems.Count; i++)
    {
    sb.Append(ObjectToString(elems[i], indent + 4));
    }
    }
    else
    {
    Type objType = obj.GetType();
    PropertyInfo[] props = objType.GetProperties();
    foreach (PropertyInfo prop in props)
    {
    if (prop.GetIndexParameters().Length == 0)
    {
    object propValue = prop.GetValue(obj);
    var elems = propValue as IList;
    if (elems != null)
    {
    foreach (var item in elems)
    {
    sb.Append($"{indentString}- {prop.Name} :\n");
    sb.Append(ObjectToString(item, indent + 4));
    }
    }
    else if (prop.Name != "ExtensionData")
    {
    sb.Append($"{indentString}- {prop.Name} = {propValue}\n");
    if (prop.PropertyType.Assembly == objType.Assembly)
    {
    sb.Append(ObjectToString(propValue, indent + 4));
    }
    }
    }
    else
    {
    sb.Append($"{indentString}- {prop.Name} ({prop.PropertyType.Name}): <Indexed>\n");
    }
    }
    }
    }
    return sb.ToString();
    }

    ACTUALIZACIÓN 2

    public static string ObjectToString(object obj, int indent = 0)
    {
    var sb = new StringBuilder();
    if (obj != null)
    {
    string indentString = new string(' ', indent);
    if (obj is string || obj.IsNumber())
    {
    sb.Append($"{indentString}- {obj}\n");
    }
    else if (obj.GetType().BaseType == typeof(Enum))
    {
    sb.Append($"{indentString}- {obj.ToString()}\n");
    }
    else if (obj is Array)
    {
    var elems = obj as IList;
    sb.Append($"{indentString}- [{elems.Count}] :\n");
    for (int i = 0; i < elems.Count; i++)
    {
    sb.Append(ObjectToString(elems[i], indent + 4));
    }
    }
    else
    {
    Type objType = obj.GetType();
    PropertyInfo[] props = objType.GetProperties();
    foreach (PropertyInfo prop in props)
    {
    if (prop.GetIndexParameters().Length == 0)
    {
    object propValue = prop.GetValue(obj);
    var elems = propValue as IList;
    if (elems != null)
    {
    foreach (var item in elems)
    {
    sb.Append($"{indentString}- {prop.Name} :\n");
    sb.Append(ObjectToString(item, indent + 4));
    }
    }
    else if (prop.Name != "ExtensionData")
    {
    sb.Append($"{indentString}- {prop.Name} = {propValue}\n");
    if (prop.PropertyType.Assembly == objType.Assembly)
    {
    sb.Append(ObjectToString(propValue, indent + 4));
    }
    }
    }
    else if (objType.GetProperty("Item") != null)
    {
    int count = -1;
    if (objType.GetProperty("Count") != null &&
    objType.GetProperty("Count").PropertyType == typeof(int))
    {
    count = (int)objType.GetProperty("Count").GetValue(obj, null);
    }
    for (int i = 0; i < count; i++)
    {
    object val = prop.GetValue(obj, new object[] { i });
    sb.Append(ObjectToString(val, indent + 4));
    }
    }
    }
    }
    }
    return sb.ToString();
    }
    public static bool IsNumber(this object value)
    {
    return value is sbyte
    || value is byte
    || value is short
    || value is ushort
    || value is int
    || value is uint
    || value is long
    || value is ulong
    || value is float
    || value is double
    || value is decimal;
    }
  5. -3

    He cambiado driis del código de abajo. A mí me funciona.

    public void PrintProperties(object obj, int indent)
    {
    if (obj == null)
    {
    return;
    }
    string indentString = new string(' ', indent);
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();
    foreach (PropertyInfo property in properties)
    {
    object propValue = property.GetValue(obj, null);
    if (IsSimpleType(property.PropertyType))
    {
    Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
    }
    else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
    {
    if (property.PropertyType == typeof(string[]))
    {
    Console.WriteLine("{0}{1}: {2}", indentString, property.Name, string.Join(",", (string[])propValue));
    }
    else
    {
    Console.WriteLine("{0}{1}:", indentString, property.Name);
    IEnumerable enumerable = (IEnumerable)propValue;
    foreach (object child in enumerable)
    {
    PrintProperties(child, indent + 2);
    }
    }
    }
    else
    {
    Console.WriteLine("{0}{1}:", indentString, property.Name);
    PrintProperties(propValue, indent + 2);
    }
    }
    }
    public static bool IsSimpleType(Type type)
    {
    return
    type.IsValueType ||
    type.IsPrimitive ||
    new Type[]
    { 
    typeof(String),
    typeof(Decimal),
    typeof(DateTime),
    typeof(DateTimeOffset),
    typeof(TimeSpan),
    typeof(Guid)
    }.Contains(type) ||
    Convert.GetTypeCode(type) != TypeCode.Object;
    }

Dejar respuesta

Please enter your comment!
Please enter your name here