Nhận các thuộc tính và giá trị từ đối tượng không xác định


150

Từ thế giới của PHP, tôi đã quyết định cho C # đi. Tôi đã có một tìm kiếm nhưng dường như không thể tìm thấy câu trả lời về cách thực hiện tương đương với điều này.

$object = new Object();

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

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

Tôi về cơ bản có một danh sách của một đối tượng. Đối tượng có thể là một trong ba loại khác nhau và sẽ có một tập các thuộc tính công cộng. Tôi muốn có thể có được một danh sách các thuộc tính cho đối tượng, lặp qua chúng và sau đó ghi chúng ra một tệp. Tôi nghĩ rằng điều này có liên quan đến sự phản chiếu của c # nhưng nó hoàn toàn mới đối với tôi.

Mọi sự trợ giúp sẽ rất được trân trọng.


9
Như một lưu ý phụ: có các đối tượng thuộc các loại khác nhau trong một danh sách (không có lớp cơ sở hoặc giao diện chung) không phải là một kiểu lập trình tốt, ít nhất là không có trong c #.
Albin Sunnanbo

Câu trả lời:


284

Điều này nên làm điều đó:

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 đến từ đâu?
Jonathan dos Santos

8
Không System.Reflectiongian tên @jonathan
Cocowalla

21
Không thực sự cần phải tạo một danh sách từ mảng, đơn giảnPropertyInfo[] props = input.GetType().GetProperties();
VladL 17/12/14

2
Bạn có muốn cập nhật cho câu trả lời năm 2017 bằng cách sử dụng Newtonsoft.Json.JsonConvert?
Vayne

1
@clone đó là một cách làm hoàn toàn khác. Bạn nên đăng câu trả lời nếu bạn nghĩ đó là một cách tiếp cận hợp lệ
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

Vâng, Reflection sẽ là con đường để đi. Đầu tiên, bạn sẽ lấy kiểu Typeđại diện cho kiểu (trong thời gian chạy) của thể hiện trong danh sách. Bạn có thể làm điều này bằng cách gọi GetTypephương thức trênObject . Bởi vì nó nằm trên Objectlớp, mọi đối tượng trong .NET đều có thể gọi được , vì tất cả các loại đều xuất phát từ Object( tốt, về mặt kỹ thuật, không phải tất cả mọi thứ , nhưng điều đó không quan trọng ở đây).

Khi bạn có Typecá thể, bạn có thể gọi GetPropertiesphương thức để lấy các PropertyInfothể hiện đại diện cho thông tin thời gian chạy về các thuộc tính trên Type.

Lưu ý, bạn có thể sử dụng phiên bản nạp chồng của GetPropertiesđể giúp phân loại các thuộc tính bạn lấy.

Từ đó, bạn sẽ chỉ cần viết thông tin ra một tập tin.

Mã của bạn ở trên, được dịch, sẽ là:

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

Lưu ý rằng nếu bạn muốn thông tin phương thức hoặc thông tin trường, bạn sẽ phải gọi một trong những tình trạng quá tải của GetMethodshoặc GetFieldsphương thức tương ứng.

Cũng lưu ý, đây là một điều để liệt kê các thành viên vào một tệp, nhưng bạn không nên sử dụng thông tin này để điều khiển logic dựa trên các tập thuộc tính.

Giả sử bạn có quyền kiểm soát việc triển khai các loại, bạn nên xuất phát từ một lớp cơ sở chung hoặc thực hiện một giao diện chung và thực hiện các cuộc gọi trên đó (bạn có thể sử dụng ashoặc istoán tử để giúp xác định lớp / giao diện cơ sở nào bạn đang làm việc tại thời gian chạy).

Tuy nhiên, nếu bạn không kiểm soát các định nghĩa loại này và phải điều khiển logic dựa trên khớp mẫu, thì tốt thôi.


11

tốt, trong C # nó tương tự. Đây là một trong những ví dụ đơn giản nhất (chỉ dành cho thuộc tính công cộng):

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

Để có được giá trị tài sản cụ thể từ tên tài sản

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

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

để truy cập giá trị thuộc tính của Tên từ tên chuỗi của thuộc tính

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

3

Bạn có thể sử dụng GetType - GetProperies - Linq Foreach :

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

3

Giải pháp một dòng sử dụng Linq ...

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

2

Đây là thứ tôi sử dụng để chuyển đổi IEnumerable<T>thành một DataTablecột chứa các cột đại diện cho Tcác thuộc tính, với một hàng cho mỗi mục trong 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;
}

Đây là "hơi" quá phức tạp, nhưng thực sự khá tốt để xem kết quả là gì, như bạn có thể đưa ra một List<T>ví dụ:

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

Và bạn sẽ được trả lại một DataTable với cấu trúc:

Tạo (chuỗi)
YearOfSản xuất (int)

Với một hàng cho mỗi mục trong của bạn List<Car>


1

Ví dụ này cắt tất cả các thuộc tính chuỗi của một đối tượng.

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

Tôi đã không tìm thấy điều này để làm việc trên, nói các đối tượng Ứng dụng. Tuy nhiên tôi đã thành công với

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

string rval = serializer.Serialize(myAppObj);

2
Đừng sử dụng JavaScriptSerializer nếu bạn có thể tránh nó. Có rất nhiều lý do .
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

Bạn có thể thử điều này:

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

Khi mọi mảng thực hiện giao diện IEnumerable

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.