首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C# 反射 GetType().GetProperties() 無法取得屬性值的原因與解決方案

     編輯:程式設計綜合問答

問題描述

在 C# 中使用反射獲取物件的屬性時,開發者常遇到 GetType().GetProperties() 回傳空陣列,導致無法進入 foreach 迴圈處理字串屬性。以下是一個典型的程式碼片段:

public T GetObject(T t)
{
    string temp = "";
    System.Reflection.PropertyInfo[] properties = t.GetType().GetProperties();
    foreach (System.Reflection.PropertyInfo p in properties)
    {
        if (p.PropertyType == typeof(string))
        {
            temp = p.GetValue(t, null).ToString();
            p.SetValue(t, temp + "1", null);
        }
    }
    return t;
}

調試時發現 properties 為 System.Reflection.PropertyInfo[0],完全取不到任何屬性。

核心原因

GetProperties() 預設只會取得公用的實例屬性。如果你的類別中定義的屬性是 private、protected、internal 或 static,預設行為就會忽略它們。此外,若類別只有欄位而沒有屬性,也會導致結果為空。

解決方法

1. 使用 BindingFlags 指定搜尋範圍

透過 BindingFlags 參數,可以明確要求包含非公用、靜態、實例等屬性:

var properties = t.GetType().GetProperties(
    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static
);

2. 確認類別確實定義了屬性而非欄位

屬性必須有 get/set 存取子,單純的欄位宣告(如 public string Name;)不會被 GetProperties() 找到。請改為:

public string Name { get; set; }

3. 檢查泛型型別參數 T 的實際型別

若傳入的是介面或基類別,且實際物件為衍生類別,t.GetType() 會回傳實際執行型別,這點通常沒問題;但若 T 被限制為介面,介面本身沒有屬性實作,也會取不到值。

完整修正範例

public T GetObject(T t)
{
    if (t == null) return default;

    var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
    var properties = t.GetType().GetProperties(flags);

    foreach (var p in properties)
    {
        if (p.PropertyType == typeof(string) && p.CanRead && p.CanWrite)
        {
            var value = p.GetValue(t) as string;
            if (!string.IsNullOrEmpty(value))
            {
                p.SetValue(t, value + "1");
            }
        }
    }
    return t;
}

常見陷阱提醒

  • 唯讀屬性:CanWrite 為 false 時呼叫 SetValue 會拋出例外,務必先檢查。
  • 索引屬性:帶參數的屬性(索引子)需要額外處理,GetProperties 也會取得,但 GetValue/SetValue 需傳入索引參數。
  • 效能考量:反射較慢,高頻呼叫建議快取 PropertyInfo 陣列或使用表達式樹/原始碼產生器優化。

總結

「取不到值」多半是因為預設只抓公用實例屬性。加上 BindingFlags.NonPublic | BindingFlags.Instance 並確認類別確實有 { get; set; } 屬性,即可解決大多數情況。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved