CODE-將匿名型別陣列匯成CSV
3 |
工作的專案有個小需求,使用者羅列了一堆報表匯出需求,基上都是從現存LINQ資料集合以不同條件取出不同欄位。
我想到最簡便的做法是套用Where()查詢,依需求產生匿名型別
Select(o => new {
欄位1 = o.PropA,
欄位2 = o.PropB,
欄位3 = o.PropC …
})
連欄位名稱都隨使用者指定,最後再將查詢結果轉為CSV,幾個步驟就搞定一項報表需求,進行量產。
基於以上構想,我需要一個能將任意匿名型別陣列或List自動轉成CSV的共用函數,挑戰點在於陣列元素型別未知,但這可難不倒C#,祭出Reflection就能輕鬆克服。
試寫範例如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace AnonymousTypeListReflectionTest
{
class Program
{
static void Main(string[] args)
{
var ary = "Jeffrey,Darkthread,Geek".Split(',')
.Select(o => new
{
文字 = o,
長度 = o.Length
}).ToArray();
Console.Write(convToCsv(ary));
Console.Read();
}
//將任意型別陣列輸出為CSV,第一列為標題列舉欄位名稱
static string convToCsv(Array ary)
{
//取得陣列元素的型別
Type elemType = ary.GetType().GetElementType();
PropertyInfo[] props = elemType.GetProperties();
StringBuilder sb = new StringBuilder();
//第一列輸出屬性名稱
sb.AppendLine(string.Join("\t", props.Select(o => o.Name).ToArray()));
//藉由foreach巡迴每一元件,透過Refelction取出屬性值
foreach (object elem in ary)
{
sb.AppendLine(string.Join("\t",
props.Select(o => Convert.ToString(o.GetValue(elem, null)))));
}
return sb.ToString();
}
}
}
實際寫完,程式遠比預期來得單純: 傳入參數時,將匿名型別陣列轉型成Array、GetElementType()可以找出陣列元素型別、Reflection GetProperties()跟PropertyInfo.GetValue()已是老把戲不用多說,至於分隔符號我選擇用Tab "\t"取代逗號,以省去處理屬性值內含逗號的麻煩。
就這樣,任意型別陣列轉CSV的函數就寫完囉~ 又到了感恩時刻,讓我們一起高呼: .NET好威呀!
Comments
# by Lonka
您好! 這個方法去轉CSV真的很方便。 有個問題想問一下,您在文中有提到「連欄位名稱都隨使用者指定」,就是您提到的「依需求產生匿名型別」。 我想請問的就是要如何用程式動態的依照使用者需求產生匿名型別? 感謝
# by Jeffrey
to Lonka, 文中所提情境,主要在簡化使用者提了大量報表需求時的開發。若希望能做到不需事前提規格,100%即興演出,就得實做出動態LINQ查詢,方法蠻多的,我想最簡便的是透過Dynamic LINQ程式庫。[可參考: http://blog.miniasp.com/post/2008/06/23/Introduce-LINQ-Dynamic-Query-Library.aspx]
# by Lonka
to Jeffrey, 謝謝你撥空回答我的問題,還費心的給了我一個很好的方向。Dynamic LINQ library確實能解決我的問題。感謝 :)