在 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,預設行為就會忽略它們。此外,若類別只有欄位而沒有屬性,也會導致結果為空。
透過 BindingFlags 參數,可以明確要求包含非公用、靜態、實例等屬性:
var properties = t.GetType().GetProperties(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static
);
屬性必須有 get/set 存取子,單純的欄位宣告(如 public string Name;)不會被 GetProperties() 找到。請改為:
public string Name { get; set; }
若傳入的是介面或基類別,且實際物件為衍生類別,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; } 屬性,即可解決大多數情況。