一、場景假設
假設現在有一個泛型類T的例項物件t,該T類的全部資訊都未知。
要求:列印輸出例項物件t的類名、屬性個數、屬性名、屬性的資料型別、屬性值。
二、解決問題
1、我們根據輸出的內容要求定義一個實體類如下:
public class GeneralDataModel
{
/// <summary>
/// 類名
/// </summary>
public string class_name { get; set; }
/// <summary>
/// 屬性個數
/// </summary>
public int prop_count { get; set; }
/// <summary>
/// 單個屬性的資訊
/// </summary>
public List<PropInfoItem> props { get; set; }
}
public class PropInfoItem
{
/// <summary>
/// 屬性名
/// </summary>
public string prop_name { get; set; }
/// <summary>
/// 屬性資料型別
/// </summary>
public string prop_data_type { get; set; }
/// <summary>
/// 屬性值
/// </summary>
public string prop_value { get; set; }
}
2、編寫一個方法,該方法的主要功能是解析例項物件t,並輸出步驟1中格式的內容。方法程式碼實現如下:
public static GeneralDataModel DataAnalysis<T>(T t)
{
var data_type = t.GetType();
var propInfo = data_type.GetProperties();
var list = new List<PropInfoItem>();
foreach (var item in propInfo)
{
var e = new PropInfoItem
{
prop_name = item.Name,
prop_data_type = item.PropertyType.Name,
prop_value = item.GetValue(t) == null ? "" : item.GetValue(t).ToString()
};
list.Add(e);
}
var res = new GeneralDataModel
{
class_name = data_type.Name,
prop_count = propInfo.Count(),
props = list
};
return res;
}
三、驗證方法功能
1、假設現在有一個學生類如下所示:
public class Student
{
/// <summary>
/// 學號
/// </summary>
public int no { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string name { get; set; }
/// <summary>
/// 年級
/// </summary>
public string grade { get; set; }
/// <summary>
/// 出生年月
/// </summary>
public DateTime birth { get; set; }
}
2、根據該類例項化了一個st物件如下:
var st = new Student()
{
no = 123456,
name = "張三",
grade = "六年級",
birth = DateTime.Now
};
3、呼叫DataAnalysis方法解析st,並列印輸出結果:
var res = DataAnalysis(st);
Console.WriteLine(JsonConvert.SerializeObject(res));
4、輸出結果如下:
{
"class_name": "Student",
"prop_count": 4,
"props": [
{
"prop_name": "no",
"prop_data_type": "Int32",
"prop_value": "123456"
},
{
"prop_name": "name",
"prop_data_type": "String",
"prop_value": "張三"
},
{
"prop_name": "grade",
"prop_data_type": "String",
"prop_value": "六年級"
},
{
"prop_name": "birth",
"prop_data_type": "DateTime",
"prop_value": "2022/5/7 17:21:12"
}
]
}
5、看到輸出結果後,感覺完美的解決了問題。
四、變化無常
1、因為種種原因,學生類增加了兩個屬性,同時例項化物件的建立形式也變了,變化後的形式如下:
public class Student
{
public Student()
{
}
public Student(string id_card_no, string address)
{
this.id_card_no = id_card_no;
this.address = address;
}
/// <summary>
/// 學號
/// </summary>
public int no { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string name { get; set; }
/// <summary>
/// 年級
/// </summary>
public string grade { get; set; }
/// <summary>
/// 出生年月
/// </summary>
public DateTime birth { get; set; }
/// <summary>
/// 身份證(受保護型別)
/// </summary>
protected string id_card_no { get; set; }
/// <summary>
/// 家庭地址(私有型別)
/// </summary>
private string address { get; set; }
}
var st = new Student("777888202005071111", "家庭地址私有,暫時不方便透露")
{
no = 123456,
name = "張三",
grade = "六年級",
birth = DateTime.Now
};
2、再次呼叫DataAnalysis方法解析st,並列印輸出結果:
var res = DataAnalysis(st);
Console.WriteLine(JsonConvert.SerializeObject(res));
3、輸出結果如下:
{
"class_name": "Student",
"prop_count": 4,
"props": [
{
"prop_name": "no",
"prop_data_type": "Int32",
"prop_value": "123456"
},
{
"prop_name": "name",
"prop_data_type": "String",
"prop_value": "張三"
},
{
"prop_name": "grade",
"prop_data_type": "String",
"prop_value": "六年級"
},
{
"prop_name": "birth",
"prop_data_type": "DateTime",
"prop_value": "2022/5/7 17:40:21"
}
]
}
4、看到輸出結果時,咦?怎麼似乎好像哪裡不對?新增的兩個屬性怎麼沒有被解析並輸出呢?
五、反射了解一下?
1、通過種種途徑或者查閱其他資料你瞭解到了反射的相關知識,並找到了一個名為GetRuntimeProperties的方法。
2、修改原先的解析方法程式碼如下:
public static GeneralDataModel DataAnalysis<T>(T t)
{
var data_type = t.GetType();
var refPropInfo = data_type.GetRuntimeProperties();
var list = new List<PropInfoItem>();
foreach (var item in refPropInfo)
{
var e = new PropInfoItem
{
prop_name = item.Name,
prop_data_type = item.PropertyType.Name,
prop_value = item.GetValue(t) == null ? "" : item.GetValue(t).ToString()
};
list.Add(e);
}
var res = new GeneralDataModel
{
class_name = data_type.Name,
prop_count = refPropInfo.Count(),
props = list
};
return res;
}
3、再一次呼叫DataAnalysis方法解析st,並列印輸出結果:
var res = DataAnalysis(st);
Console.WriteLine(JsonConvert.SerializeObject(res));
4、輸出結果如下:
{
"class_name": "Student",
"prop_count": 6,
"props": [
{
"prop_name": "no",
"prop_data_type": "Int32",
"prop_value": "123456"
},
{
"prop_name": "name",
"prop_data_type": "String",
"prop_value": "張三"
},
{
"prop_name": "grade",
"prop_data_type": "String",
"prop_value": "六年級"
},
{
"prop_name": "birth",
"prop_data_type": "DateTime",
"prop_value": "2022/5/7 17:52:12"
},
{
"prop_name": "id_card_no",
"prop_data_type": "String",
"prop_value": "777888202005071111"
},
{
"prop_name": "address",
"prop_data_type": "String",
"prop_value": "家庭地址暫時不方便透露"
}
]
}
5、看到這輸出結果,臉上露出了滿意的笑容,啊~~~問題終於解決了,開森^_^
六、前後對比並溯源
1、方法前後變化僅僅只有一處,由GetProperties
變為了GetRuntimeProperties
。
2、溯源發現:
- GetProperties:在System名稱空間下,是Type類的例項方法。
- GetRuntimeProperties(Type類的擴充套件方法):在System.Reflection名稱空間下,是RuntimeReflectionExtensions類的靜態方法。
--------------The End--------------
----------本篇文章到此結束----------