Obter propriedades e valores de objeto desconhecido

150

No mundo do PHP, decidi tentar o C #. Eu fiz uma pesquisa, mas não consigo encontrar a resposta de como fazer o equivalente a isso.

$object = new Object();

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

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

Basicamente, tenho uma lista de um objeto. O objeto pode ser um dos três tipos diferentes e terá um conjunto de propriedades públicas. Quero poder obter uma lista das propriedades do objeto, fazer um loop sobre elas e depois gravá-las em um arquivo. Eu estou pensando que isso tem algo a ver com a reflexão c #, mas é tudo novo para mim.

Qualquer ajuda seria muito apreciada.

m4rc
fonte
9
Como uma observação lateral: ter objetos de tipos diferentes em uma lista (sem uma classe base ou interface comum) não é um bom estilo de programação, pelo menos não em c #.
Albin Sunnanbo

Respostas:

284

Isso deve servir:

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
fonte
De onde vem o PropertyInfo?
Jonathan dos Santos
8
@jonathan System.Reflectionnamespace
Cocowalla
21
Não há realmente precisa para criar uma lista de matriz, simplesmentePropertyInfo[] props = input.GetType().GetProperties();
VladL
2
Deseja atualizar para a resposta de 2017 usando Newtonsoft.Json.JsonConvert?
Vayne
1
@ Clone é uma maneira completamente diferente de fazer isso. Você deve postar uma resposta se achar que é uma abordagem válida #
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
fonte
17

Sim, a reflexão seria o caminho a percorrer. Primeiro, você obteria o Typeque representa o tipo (em tempo de execução) da instância na lista. Você pode fazer isso chamando o GetTypemétodo emObject . Por estar na Objectclasse, é possível chamar todos os objetos no .NET, pois todos os tipos derivam Object( bem, tecnicamente, nem tudo , mas isso não é importante aqui).

Depois de ter a Typeinstância, você pode chamar o GetPropertiesmétodo para obter as PropertyInfoinstâncias que representam as informações em tempo de execução sobre as propriedades no Type.

Observe que você pode usar as sobrecargas de GetPropertiespara ajudar a classificar quais propriedades você recupera.

A partir daí, basta escrever as informações em um arquivo.

Seu código acima, traduzido, seria:

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

Observe que, se você quiser informações sobre o método ou informações sobre o campo, precisará chamar uma das sobrecargas dos métodos GetMethodsou GetFields, respectivamente.

Observe também que uma coisa é listar os membros em um arquivo, mas você não deve usar essas informações para conduzir a lógica com base nos conjuntos de propriedades.

Supondo que você tenha controle sobre as implementações dos tipos, você deve derivar de uma classe base comum ou implementar uma interface comum e fazer as chamadas (você pode usar o operador asor ispara ajudar a determinar com qual classe / interface base você está trabalhando. tempo de execução).

No entanto, se você não controla essas definições de tipo e precisa conduzir a lógica com base na correspondência de padrões, tudo bem.

casperOne
fonte
11

bem, em C # é semelhante. Aqui está um dos exemplos mais simples (apenas para propriedades 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
fonte
9

Para obter um valor específico da propriedade do nome da propriedade

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

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

para acessar o valor da propriedade Name a partir da string name of property

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

Você pode usar GetType - GetProperties - Linq Foreach :

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

Solução de uma linha usando Linq ...

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

Aqui está algo que eu uso para transformar um IEnumerable<T>em um DataTableque contém colunas representando Tas propriedades de, com uma linha para cada item no 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;
}

Isso é "um pouco" complicado demais, mas é realmente muito bom ver qual é o resultado, como você pode dar um List<T>exemplo, por exemplo:

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

E você receberá uma DataTable com a estrutura:

Marca (string)
YearOfManufacture (int)

Com uma linha por item no seu List<Car>

Roubar
fonte
1

Este exemplo apara todas as propriedades de sequência de um 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
fonte
0

Não encontrei isso para trabalhar, digamos, Objetos de aplicativo. No entanto, tive sucesso com

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

string rval = serializer.Serialize(myAppObj);
jcsubmit
fonte
2
Não use JavaScriptSerializer se puder evitá-lo. Existem muitas razões .
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
fonte
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
fonte
-1

Você pode tentar isso:

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

Uma vez que cada array implementa a interface IEnumerable

Pablo Rocha Villagra
fonte