分享程式代碼相關筆記
目前文章總數:157 篇
最後更新:2024年 12月 07日
以下圖為例,在.net中用反射是取不到ViewModel Class中Property的Summary
原因是這個Summary是紀錄於Xml中,而不是在建置階段時存於 .NET assembly
一種解法是將Xml檔案匯出到指定位址,讀取並做解析
對Visual Studio專案 -> 滑鼠右鍵 -> 屬性
依序選擇:”建置” -> “輸入” -> “產生包含API文件的檔案”打勾
打勾完成後”建置”專案,使其產生.xml檔案
※這是Visual Studio 2022 的畫面,每個版本屬性裡面多少會有差異
對Visual Studio專案 -> 滑鼠右鍵 -> 在檔案總管中開啟資料夾
檔案路徑會在Debug 或 Release 底下,這邊是Debug的路徑下
$\bin\Debug\net6.0-windows\GetClassAndPropertyDescriptionExample.xml
開啟XML檔案後,與原範例專案比較可以發現Class內的所有Summary資訊都可以匹配到
範例專案架構如下,檔案3個
1. 主程式:所有的轉換邏輯與取得路徑與畫面顯示皆在此檔案
2. 原Class:ViewMode含有的Property與Summary
3. 改Class:在第3部分應用章節用到,為對應原Class ViewModel的Property與Summary
介面如下,主要有3個區塊
1. 輸入ClassName:輸入ViewModel的完整路徑,才可以查出Class
2. 功能區塊:主要有3個功能,第二部分會介紹 “1.查詢” 功能
3. 輸出結果:執行的結果會顯示在此
開啟範例檔案中的Class檔案,取得 命名空間 + ClassName
並且組成後貼到下面的TextBox上
按下查詢後,可以取得該Class的Summary 與Propery Name
開啟主程式代碼,會有關於”1.查詢” 按鈕的功能Region
1. 點擊查詢按鈕事件
2. 檢核 Xml檔案是否存在
3. 解析XML檔案,並回傳到UI畫面上
_docuDoc.Load(_xmlPath);
2. 取得Property屬性的資料 P: 開頭
_docuDoc.SelectNodes("//member[starts-with(@name, '" + $@"P:{className}" + "')]");
3. Regex 正則表示式截斷出資料
var dictionary = new Dictionary<string, string>();
Regex filter = new Regex(@"\..*$");
for (int i = 0; i < xmlDocuOfMethod.Count; i++)
{
var nameTag = xmlDocuOfMethod[i].Attributes["name"].Value.Replace(className, "");
var name = filter.Match(nameTag).Value.Replace(".", ""); ;
var summary = xmlDocuOfMethod[i].InnerText;
dictionary.Add(name, summary);
}
4. 最後輸出到畫面上,完整代碼如下:
/// <summary>
/// 【1】 取得特定的Class裡面的PropertyName 與 Summary
/// </summary>
private void GetSpecifyClassNameInfomation(string className)
{
var _docuDoc = new System.Xml.XmlDocument();
_docuDoc.Load(_xmlPath);
var xmlDocuOfMethod = _docuDoc.SelectNodes(
"//member[starts-with(@name, '" + $@"P:{className}" + "')]");
if (xmlDocuOfMethod != null)
{
var dictionary = new Dictionary<string, string>();
Regex filter = new Regex(@"\..*$");
for (int i = 0; i < xmlDocuOfMethod.Count; i++)
{
var nameTag = xmlDocuOfMethod[i].Attributes["name"].Value.Replace(className, "");
var name = filter.Match(nameTag).Value.Replace(".", ""); ;
var summary = xmlDocuOfMethod[i].InnerText;
dictionary.Add(name, summary);
}
var resultString = new StringBuilder();
foreach (var dicItem in dictionary)
{
resultString.AppendLine($"PropertyName:{dicItem.Key}");
resultString.AppendLine($"Summary:{dicItem.Value.Replace("\r\n", "").Trim()}");
resultString.AppendLine();
}
ConverttextBoxMessage.Text = resultString.ToString();
}
}
假設有一需求:需要將原本的Login物件裡面的名稱全部重新命名,但原本的要保留
並且新的Login物件要與原本的Login物件 1對1
假設Property有100個項目,用手寫必定會瘋掉,這時就可以借助XML解析的方式
開啟範例檔案中的Change.LoginViewModel.cs 的檔案,取得 命名空間 + ClassName
並且組成後貼到下面的TextBox上
開啟主程式代碼,會有關於”2.轉換對應物件按鈕” 按鈕的功能Region
1. 轉換對應物件按鈕
2. 取得客製的Mapping 代碼
var resultString = new StringBuilder();
foreach (var dicItem in dictionary)
{
string path = "P:" + className + "." + dicItem.Key;
XmlNode findXmlDocuOfMethod = _docuDoc.SelectSingleNode(
"//member[starts-with(@name, '" + path + "')]");
var filterWord = new Regex(@"[A-Za-z0-9]+");
var match = filterWord.Match(findXmlDocuOfMethod.InnerText.Replace("\r\n", ""));
//match.Groups[0].Value 取得原名稱
//prop.Name 取得新名稱
if (match.Success)
{
resultString.AppendLine($@"{dicItem.Key} = input.{match.Groups[0].Value},");
}
}
4. 最後輸出到畫面上,完整代碼如下:
/// <summary>
/// 【2】 取得客製的Mapping 代碼
/// </summary>
private void GetSpecifyClassNameConvertObjecString(string className)
{
var _docuDoc = new System.Xml.XmlDocument();
_docuDoc.Load(_xmlPath);
var xmlDocuOfMethod = _docuDoc.SelectNodes(
"//member[starts-with(@name, '" + $@"P:{className}" + "')]");
if (xmlDocuOfMethod != null)
{
var dictionary = new Dictionary<string, string>();
Regex filter = new Regex(@"\..*$");
for (int i = 0; i < xmlDocuOfMethod.Count; i++)
{
var nameTag = xmlDocuOfMethod[i].Attributes["name"].Value.Replace(className, "");
var name = filter.Match(nameTag).Value.Replace(".", ""); ;
var summary = xmlDocuOfMethod[i].InnerText;
dictionary.Add(name, summary);
}
var resultString = new StringBuilder();
foreach (var dicItem in dictionary)
{
string path = "P:" + className + "." + dicItem.Key;
XmlNode findXmlDocuOfMethod = _docuDoc.SelectSingleNode(
"//member[starts-with(@name, '" + path + "')]");
var filterWord = new Regex(@"[A-Za-z0-9]+");
var match = filterWord.Match(findXmlDocuOfMethod.InnerText.Replace("\r\n", ""));
//match.Groups[0].Value 取得原名稱
//prop.Name 取得新名稱
if (match.Success)
{
resultString.AppendLine($@"{dicItem.Key} = input.{match.Groups[0].Value},");
}
}
ConverttextBoxMessage.Text = resultString.ToString();
}
}
另一種方法是將代碼裡的指定Class,直接進行轉換
執行按鈕”3.轉換已存在物件”
如下執行結果可以直接取得
開啟主程式代碼,會有關於”3.轉換已存在物件” 按鈕的功能Region
1. 按鈕事件-取得強型別類型的物件內容方法
2. 泛型物件轉換,將指定的Class丟進去做轉換
var properties = typeof(T).GetProperties();
foreach (var prop in properties)
{
//prop.Name
}
3. 完整泛型轉換代碼如下
/// <summary>
///【3】 泛型物件轉換
/// </summary>
private void LoadXml<T>()
{
var properties = typeof(T).GetProperties();
var _docuDoc = new System.Xml.XmlDocument();
_docuDoc.Load(_xmlPath)
var resultString = string.Empty;
foreach (var prop in properties)
{
var fullname = prop.DeclaringType.FullName.Replace('+', '.');
string path = "P:" + fullname + "." + prop.Name
XmlNode xmlDocuOfMethod = _docuDoc.SelectSingleNode(
"//member[starts-with(@name, '" + path + "')]");
Regex filter = new Regex(@"([A-Za-z]+)");
var match = filter.Match(xmlDocuOfMethod.InnerText.Replace("\r\n", ""));
//match.Groups[0].Value 取得原名稱
//prop.Name 取得新名稱
if (match.Success)
{
resultString += $@"{prop.Name} = input.{match.Groups[0].Value}," + Environment.NewLine;
}
ConverttextBoxMessage.Text = resultString;
}
}