Отримати властивості та значення з невідомого об'єкта


150

Зі світу PHP я вирішив подати C #. У мене був пошук, але не можу знайти відповідь, як зробити еквівалент цьому.

$object = new Object();

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

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

У мене в основному є список об’єктів. Об'єкт може бути одного з трьох різних типів і матиме набір загальнодоступних властивостей. Я хочу мати змогу отримати список властивостей об’єкта, перекиньте їх і потім запишіть їх у файл. Я думаю, що це має щось спільне з відображенням c #, але для мене це все нове.

Будь-яка допомога буде дуже вдячна.


9
Як бічне зауваження: наявність об’єктів різних типів у списку (без загального базового класу чи інтерфейсу) - це не гарний стиль програмування, принаймні не в c #.
Альбін Суннанбо

Відповіді:


284

Це слід зробити:

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
}

звідки береться PropertyInfo?
Джонатан дос Сантос

8
@ Джонатан System.Reflectionімен
Cocowalla

21
Створювати список із масиву справді не потрібно, простоPropertyInfo[] props = input.GetType().GetProperties();
VladL

2
Ви хочете оновити відповідь 2017 року, використовуючи Newtonsoft.Json.JsonConvert?
Вайне

1
@clone - це зовсім інший спосіб зробити це. Ви повинні опублікувати відповідь, якщо вважаєте, що це правильний підхід
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

Так, Рефлексія була б дорогою. По-перше, ви отримаєте те, Typeщо представляє тип (під час виконання) екземпляра у списку. Це можна зробити, зателефонувавши на GetTypeметодObject . Оскільки він знаходиться в Objectкласі, він може викликати кожен об’єкт в .NET, оскільки всі типи походять від Object( ну, технічно, не все , але це не важливо тут).

Як тільки у вас є Typeпримірник, ви можете викликати GetPropertiesметод, щоб отримати PropertyInfoекземпляри, які представляють інформацію про час роботи про властивості в Type.

Зверніть увагу, ви можете використовувати перевантаження, GetPropertiesщоб допомогти класифікувати, які властивості ви шукаєте.

Звідти ви просто записуєте інформацію у файл.

Ваш код, перекладений вище, буде таким:

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

Зауважте, що якщо ви хочете інформацію про метод або інформацію про поле, вам доведеться викликати одне з перевантажень GetMethodsабо GetFieldsметодів відповідно.

Також зауважте, що одне з них має перелічити членів у файлі, але ви не повинні використовувати цю інформацію для керування логікою на основі наборів властивостей.

Якщо припустити, що ви маєте контроль над реалізацією типів, вам слід виходити із загального базового класу або впроваджувати загальний інтерфейс і здійснювати дзвінки по цим (ви можете скористатися оператором asабо isоператором, щоб визначити, для якого базового класу / інтерфейсу ви працюєте час виконання).

Однак, якщо ви не керуєте цим визначенням і доводиться керувати логікою на основі відповідності шаблонів, то це добре.


11

ну, в C # це схоже. Ось один із найпростіших прикладів (лише для загальнодоступних ресурсів):

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

Щоб отримати конкретне значення властивості від назви властивості

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

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

для доступу до значення властивості Name з назви рядка властивості

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

3

Ви можете використовувати GetType - GetProperties - Linq Foreach :

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

3

Одне рядкове рішення за допомогою Linq ...

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

2

Ось те, що я використовую для перетворення IEnumerable<T>в, DataTableщо містить стовпці, що представляють Tвластивості, з одним рядком для кожного елемента в 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;
}

Це "дещо" ускладнюється, але насправді дуже добре бачити, який результат, як ви можете дати йому List<T>, наприклад:

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

І вам буде повернуто таблицю даних зі структурою:

Зробити (рядок)
YearOfManufacture (int)

З одним рядком на елемент у вашому List<Car>


1

Цей приклад обрізає всі рядкові властивості об'єкта.

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

Я не знайшов, щоб це працювало, скажімо, об'єкти Application. Однак у мене був успіх

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

string rval = serializer.Serialize(myAppObj);

2
Не використовуйте JavaScriptSerializer, якщо зможете цього уникнути. Причин дуже багато .
Нуно Андре

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

Ви можете спробувати це:

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

Раз кожен масив реалізує інтерфейс IEnumerable

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.