Uzyskaj właściwości i wartości z nieznanego obiektu


150

Ze świata PHP postanowiłem spróbować C #. Szukałem, ale nie mogę znaleźć odpowiedzi, jak zrobić odpowiednik tego.

$object = new Object();

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

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

Zasadniczo mam listę obiektu. Obiekt może być jednym z trzech różnych typów i będzie miał zestaw właściwości publicznych. Chcę mieć możliwość uzyskania listy właściwości obiektu, zapętlenia nad nimi, a następnie zapisania ich do pliku. Myślę, że ma to coś wspólnego z odbiciem C #, ale to wszystko jest dla mnie nowe.

Każda pomoc byłaby bardzo mile widziana.


9
Na marginesie: posiadanie obiektów różnych typów na liście (bez wspólnej klasy bazowej lub interfejsu) nie jest dobrym stylem programowania, przynajmniej nie w języku C #.
Albin Sunnanbo

Odpowiedzi:


284

To powinno wystarczyć:

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
}

skąd pochodzi PropertyInfo?
Jonathan dos Santos

8
@jonathan System.Reflectionnazw
Cocowalla

21
Naprawdę nie ma potrzeby tworzenia listy z tablicy, po prostuPropertyInfo[] props = input.GetType().GetProperties();
VladL

2
Czy chcesz zaktualizować odpowiedź w 2017 roku za pomocą Newtonsoft.Json.JsonConvert?
Vayne,

1
@clone to zupełnie inny sposób na zrobienie tego. Powinieneś zamieścić odpowiedź, jeśli uważasz, że to słuszne podejście
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

Tak, Refleksja byłaby właściwą drogą. Po pierwsze, otrzymasz, Typektóry reprezentuje typ (w czasie wykonywania) instancji na liście. Możesz to zrobić, wywołując GetTypemetodęObject . Ponieważ znajduje się w Objectklasie, jest wywoływany przez każdy obiekt w .NET, ponieważ wszystkie typy pochodzą z Object( no, technicznie nie wszystko , ale to nie jest ważne).

Gdy masz już Typeinstancję, możesz wywołać GetPropertiesmetodę, aby uzyskać PropertyInfoinstancje, które reprezentują informacje w czasie wykonywania o właściwościach w Type.

Uwaga, można skorzystać z przeciążeniem GetPropertiesułatwia klasyfikowanie której właściwości mają odzyskać.

Stamtąd po prostu zapisujesz informacje do pliku.

Twój powyższy kod, przetłumaczony, wyglądałby tak:

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

Zauważ, że jeśli chcesz uzyskać informacje metoda lub informacji pole, trzeba by zadzwonić do jednego z tych przeciążeń GetMethodslub GetFieldsmetod odpowiednio.

Zauważ też, że jedną rzeczą jest wyszczególnienie członków pliku, ale nie powinieneś używać tych informacji do sterowania logiką opartą na zestawach właściwości.

Zakładając, że masz kontrolę nad implementacjami typów, powinieneś wyprowadzić ze wspólnej klasy bazowej lub zaimplementować wspólny interfejs i wykonać na nich wywołania (możesz użyć operatora aslub is, aby pomóc określić, z którą klasą bazową / interfejsem pracujesz runtime).

Jeśli jednak nie kontrolujesz tych definicji typów i musisz sterować logiką opartą na dopasowywaniu wzorców, to jest w porządku.


11

cóż, w C # jest podobnie. Oto jeden z najprostszych przykładów (tylko dla usług publicznych):

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

Aby uzyskać określoną wartość właściwości z nazwy właściwości

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

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

aby uzyskać dostęp do wartości właściwości Name z ciągu nazwa właściwości

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

3

Możesz użyć GetType - GetProperties - Linq Foreach :

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

3

Rozwiązanie jednoprzewodowe wykorzystujące Linq ...

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

2

Oto coś, czego używam do przekształcenia an IEnumerable<T>w a, DataTablektóre zawiera kolumny reprezentujące Twłaściwości, z jednym wierszem na każdy element w 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;
}

Jest to „nieco” przesadnie skomplikowane, ale w rzeczywistości jest całkiem dobre, aby zobaczyć, jaki jest wynik, ponieważ możesz dać mu List<T>na przykład:

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

Zostanie Ci zwrócony DataTable o strukturze:

Marka (string)
YearOfManufacture (int)

Z jednym wierszem na element w pliku List<Car>


1

Ten przykład przycina wszystkie właściwości ciągu obiektu.

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

Nie znalazłem tego do pracy, powiedzmy obiekty aplikacji. Miałem jednak sukces z

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

string rval = serializer.Serialize(myAppObj);

2
Nie używaj JavaScriptSerializer, jeśli możesz tego uniknąć. Powodów jest wiele .
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;
}

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

Możesz spróbować tego:

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

Gdy każda tablica implementuje interfejs IEnumerable

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.