รับคุณสมบัติและค่าจากวัตถุที่ไม่รู้จัก


150

จากโลกของ PHP ฉันตัดสินใจเลิก C # ฉันเคยค้นหา แต่ดูเหมือนไม่สามารถหาคำตอบของวิธีการที่เทียบเท่ากับสิ่งนี้

$object = new Object();

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

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

โดยทั่วไปฉันมีรายการวัตถุ วัตถุอาจเป็นหนึ่งในสามประเภทที่แตกต่างกันและจะมีชุดของคุณสมบัติสาธารณะ ฉันต้องการที่จะได้รับรายการคุณสมบัติสำหรับวัตถุวนรอบพวกเขาแล้วเขียนออกไปยังไฟล์ ฉันคิดว่าสิ่งนี้เกี่ยวข้องกับการไตร่ตรองด้วย c # แต่มันใหม่ทั้งหมดสำหรับฉัน

ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมอย่างมาก.


9
ในฐานะที่เป็นหมายเหตุด้านข้าง: การมีออบเจ็กต์ประเภทต่าง ๆ ในรายการ (ไม่มีคลาสพื้นฐานหรืออินเตอร์เฟส) ไม่ใช่รูปแบบการเขียนโปรแกรมที่ดีอย่างน้อยไม่ใช่ใน c #
Albin Sunnanbo

คำตอบ:


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 มาจากไหน
Jonathan dos Santos

8
@jonathan System.Reflectionnamespace
Cocowalla

21
ไม่จำเป็นต้องสร้างรายการจากอาร์เรย์จริงๆเพียงแค่PropertyInfo[] props = input.GetType().GetProperties();
VladL

2
คุณต้องการอัปเดตสำหรับคำตอบปี 2017 ที่ใช้Newtonsoft.Json.JsonConvertหรือไม่
Vayne

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กรณีที่เป็นตัวแทนของ informationa 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);
}

โปรดทราบว่าหากคุณต้องการข้อมูลวิธีการหรือข้อมูลภาคสนามคุณจะต้องเรียกใช้หนึ่งใน overloads ของ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"};

เพื่อเข้าถึงค่าคุณสมบัติของชื่อจากชื่อสตริงของคุณสมบัติ

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


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>a 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; }
}

และคุณจะถูกส่งคืน DataTable พร้อมโครงสร้าง:

ทำ (สตริง)
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

ฉันไม่พบสิ่งนี้เพื่อใช้งานได้พูดแอปพลิเคชันวัตถุ แต่ฉันก็ประสบความสำเร็จด้วย

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

string rval = serializer.Serialize(myAppObj);

2
อย่าใช้ JavaScriptSerializer หากคุณสามารถหลีกเลี่ยงได้ มีเหตุผลมากมาย
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

คุณสามารถลองสิ่งนี้:

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

เมื่อทุกอาร์เรย์ใช้อินเทอร์เฟซ IEnumerable

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.