2012-07-09 30 views
4

我們有一個文件格式,我們需要分析,看起來像:序列屬性在C#類

v1|000|sammy|endpoint|blah 

這是一個有序的固定寬度格式的供應商提供給我們,所以每個那些5個的地圖到類中的特定屬性(實際格式大於30)。

我想通過對屬性應用順序來解析這個問題。我可以做的一件事就是自己創建一些東西 - 編寫一個採用單個數字的Attribute類,並將該屬性應用到每個屬性及其序列索引,並在OrderBy子句中的Reflection中查找它。

在C#中有現成的或更好的方法嗎?例如,這是否已經有一個屬性?有沒有辦法在C#或甚至MSIL中詢問在一個類中聲明瞭哪些訂單屬性?

+0

這取決於。有許多方法,但它們不能保證可以工作,它們依賴於實現細節,這些細節可能會在更新版本的編譯器和更新版本的.NET Framework中發生變化。你想要一個解決方案有多可靠? – hvd 2012-07-09 16:25:35

+3

爲什麼要使用反射?它比編寫一個裝載器類相對較慢且更復雜,該裝載器類具有如何將一系列字符映射到給定屬性的知識。 – 2012-07-09 16:26:41

+0

@ hvd只要我能用單元測試捕捉編譯器驅動的中斷,對於任何我能想象的解決方案來說,這都應該是微不足道的,我會接受簡單性,這對於未來的編譯器更改可能很脆弱。 – 2012-07-09 18:50:39

回答

3

使用PropertyInfo.MetadataToken可以看到元數據中出現的屬性的順序。恰巧當前編譯器會使該順序與源代碼中屬性的顯示順序相匹配,因此按MetadataToken排序,您將獲得與源代碼中相同的順序。

聲明:未來的編譯器可能會改變這一點。如果沒有理由,它可能不會,但如果編譯器例如變成多線程的話,可能需要額外的不必要的努力來保持原始的順序。如果您依賴於此,請確保在出現故障時更新.NET Framework時出現嚴重錯誤,而不是靜默運行時損壞。

1

如果您想使用基於屬性的方法,我個人會爲此創建自定義屬性。這不是一個「標準」操作,所以在框架中沒有(適當的)屬性可以用來裝飾你的類。

我的方法很可能是一個類級屬性,它接受列表中每個條目的屬性名稱的字符串數組,或者沿着這些行的東西。

這就是說,我質疑基於屬性的方法是否是正確的方法。您可能需要某種類型的管理員類來介導此操作,因爲某些操作需要執行「反射」過程。讓這個類管理這裏的關係可能更有意義,特別是因爲它已經需要關於類層次結構的知識(爲了首先構建類)。

在這一點上,擁有一個可以直接構造對象的自定義類或方法會更好地執行,更易於維護,並且比嘗試使用反射並動態執行此操作要簡單得多。

+0

這個概念是我想通過類似DelimitedData.Parse (str),並且DelimitedData類查看序列的屬性,拆分字符串,並將字段分配到模型中的屬性以正確的順序。 +1用於通過明確的列表保存訂單。儘管如此,你的解決方案會加倍工作,並且會失去編譯時檢查該列表中的拼寫錯誤。 – 2012-07-10 18:49:17

1

您使用的是.net 4.0嗎?這看起來就像dynamic keyword的創建情況。也就是說,順序和一致性似乎比任何時候發生的特定類型都要重要,所以你可以隨便任意指定標題,數據,無論哪種規則讓你快樂,然後將它們拉回來使用相同的規則。這也可能(大概)允許你不使用反射,這總是一個加號。

+0

我想稍後使用靜態屬性名稱進行值綁定的好處 - 例如,我將此模型傳遞給日誌記錄事件和視圖。我也不確定使用動態過度反射的性能好處 - 我期望CLR處理這兩種情況的成本相似。 – 2012-07-10 18:44:36

+0

我不能說我曾經直接使用動態來比較使用反射,但處理動態調用的DLR在邏輯上覆蓋了CLR,所以動態關鍵字的使用決不應該觸及CLR。這實際上主要是好奇心,如果你傳遞了一堆東西,我可能也會傾向於靜態屬性名稱。 – tmesser 2012-07-10 18:48:55

0

你可以看看實現類似於Google's Protocol Buffers的東西。

目前沒有C#實現(我知道),但提供的文檔非常好,應該給你一些比反射慢得多並且通常比較複雜的想法。

1

現在,如果性能不是一個大問題,並且您正在使用Reflection,那麼獲取沒有屬性的映射的簡單方法是使用RegEx使用組進行解析。與此相似的實現: Read fixed width record from text file

使用正則表達式,如:

"^(?<Field1>.{6})(?<Field2>.{16})(?<Field3>.{12})" 

既然你可以自己定義組的名稱,你可以明智地選擇了名稱,以完全符合您的屬性名稱,和這樣使用反射自動映射,而不使用屬性。

編輯: 既然你會最終有一個字符串,它會不會很「重構友好」裏面的屬性名稱我強烈推薦單元測試這種徹底保證重新命名的屬性將打破測試何時產生不匹配。

+0

另一個好建議。可以通過在構建上述Regex時使用Reflection來解決編譯安全問題,並且一旦編譯了Regex,轉換應該相當快。我的意思是,你可以用幾個小表達式來構建它,然後像這樣得到他們的名字:http://stackoverflow.com/questions/3778598/get-string-property-name-from-expression但是,這可能足夠複雜保證簡單地使用FileHelper解決方案也在這裏提出。 – 2012-07-11 02:55:07

0

當然也有很多可能的答案在這裏,所以這裏有一個馬馬虎虎一個我碰到:

有一個在System.ComponentModel.DataAnnotations現有屬性(在.net 4.5 +,它移動到系統.ComponentModel.DataAnnotations.Schema)命名ColumnAttribute:

http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.schema.columnattribute(v=vs.110

你可以用它喜歡:

[Column(Order=1)] 
public string Version { get; set; } 

[Column(Order=2)] 
public string Id { get; set; } 

但是,如果固定寬度格式發生變化,這顯然很麻煩 - 你必須手動進入並更改你輸入的30多個序號,如果說,字段是在開頭添加的。由於在這種情況下,我們不控制格式,並且未來的版本可能會頻繁出現,所以從類中輸入順序屬性的順序來找到具有隱含順序的東西將很好。