2010-06-10 63 views
6

我想解析一個c#文件。我唯一想要的是確定它是否包含具有特定名稱的財產;只是一個簡單的真實/虛假的迴應。或者說,因爲我會在每次運行檢查多個屬性,提取屬性名稱的列表,可幫助從c#源文件中提取屬性名稱

我以爲我可以使用CodeDomProvider功能(F#示例)創建一個完美的解決方案:

use reader = new StreamReader(existingFile) 
let codeProvider = new CSharpCodeProvider() 
let codeUnit = codeProvider.Parse(reader) 

不幸的是,Parse函數沒有爲CSharpCodeProvider實現。有沒有辦法從源文件中獲得CodeCompileUnit?還是有另一種優雅的方式? (我本來希望避免這個問題的正則表達式)?

編輯: 我打算用它來自動生成代碼。基本上,我要在文件xyz.partial.cs中生成一個部分類。這將生成一個骨架屬性。但是,如果我想更改屬性的實現,我將剪切該屬性並將其粘貼到手工編碼的xyz.cs.重新生成生成的類時,我希望它跳過生成已移至手動編碼文件的屬性。

因此,反射是沒有問題的,因爲反射會告訴我該屬性確實存在,但不是如果它在一個或另一個文件中定義。

+0

不過,我很想打開Expresso並給它一個鏡頭。我可以經常表達任何東西,而不是'詩句中的權力可以阻止我。 – 2010-06-10 13:39:30

+1

您是否考慮過對源代碼的編譯版本的反思?或者這不是一個選擇?不知道反射是否提供了屬性名稱。 – 2010-06-10 13:54:14

+0

@Moron - 這實際上應該工作得很好。 – ChaosPandion 2010-06-10 14:59:00

回答

0

有時正則表達式是唯一優雅的解決方案。這應該是你在找什麼。它會給你每個屬性的名稱在代碼文件中,僅此而已:

(?:"(?:(?:(?:\\.)|[^"\\\r\n])*)"|'(?:(?:(?:\\.)|[^'\\\r\n])*)'|@"(?:(?:(?:"")|[^"])*)")|(?:(?://.*)|(?:/\*(?:(?:[^*]|\*(?!/))*)\*/))|(?:[\w?<>]\s+(\w+)\s*\{\s*(?:get|set)\s*[{;]) 

它不會在註釋或字符串匹配類似的代碼,只需要一個小的修改,返回屬性的類型。該名稱出現在capture \ 1中,但如果不是真正的匹配,則該名稱將爲空白。

+2

你稱之爲「優雅」? 「有些人在遇到問題時想」我知道,我會用正則表達式「。現在他們有兩個問題」 – 2010-06-11 09:36:06

+0

你會用什麼?嵌套循環和子串?一個數字不合適,你有一個難以預料的問題爆發。正則表達式對我來說從來都不是問題,並且通常只用一行代碼完成工作。效率更高。 – Patrick 2010-06-11 17:55:43

+0

我意識到我可能需要使用正則表達式,這個讓我開始,但有一些東西,它不匹配:具有泛型或可空類型的屬性(因爲類型的名稱不是以字符結尾,但是一個?或一個>),並且它不匹配自動屬性(具有自動後臺字段的屬性) – Pete 2010-06-14 09:32:01

1

編輯2:基於增加的信息,我會說你最好編譯手動編碼的類,然後反映這個類。然後您可以生成部分類文件的代碼。

編輯:我已經做了一些更多的研究,看起來你運氣不好。 CodeDom不能用於解析代碼。 http://blogs.msdn.com/b/bclteam/archive/2005/03/16/396929.aspx

有一個關於如何在MSDN上創建CSharpCodeProvider實例的示例。

CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); 
CodeCompileUnit ccu = provider.Parse(reader); 

然後,您可以瀏覽CodeCompileUnit(上CodeCompileUnit更多的文檔)。

希望它有幫助。

+0

它看起來像Parse方法沒有被所有的CodeDomProvider類實現。原來的問題聽起來像它沒有被C#實現。任何人都知道嗎? – 2010-06-10 22:38:10

+0

它們在運行時實現,我認爲。您是否嘗試過實際運行代碼?除非它在運行時拋出異常,否則我建議你試試看。 – 2010-06-11 10:48:29

+0

我就是這樣開始的。它給出了相同的結果NotImplementedException。 CodeDomProvider.CreateProvider(「CSharp」)只是返回一個CSharpCodeProvider。 – Pete 2010-06-11 14:50:06

0

我想你可以通過在運行時使用PropertyInfo來解決這個問題。它使用反射來返回一個類型的所有信息。從類型獲得所有屬性名稱,試試這個:

void GetMeTheProperties(object source) 
{ 
    Type sourceType = source.GetType(); 

    foreach (PropertyInfo sourceProperty in sourceType.GetProperties()) 
    { 
     int i = 1; 
     Console.WriteLine("Property {0}: {1}", i, sourceProperty.Name; 
    } 
} 

您還可以確定特定命名的屬性是一種用類似的方法:

bool PropertyExists(string propertyName, object source) 
{ 
    Type sourceType = source.GetType(); 
    return (from var s in sourceType.GetProperties() select s).Where(i => i.Name == propertyName).Any(); 
} 
+0

不幸的是,反射不是一個選項,請參閱編輯爲什麼 – Pete 2010-06-11 15:00:02

+0

對不起......誤解了這個問題。 – Odhran 2010-06-11 16:28:40

0

是文件你從編譯生成的代碼?如果是這樣,你可以嘗試創建一個屬性添加到所有不應該被複制的屬性。然後,您可以使用反射來讀取屬性並跳過這些屬性。

internal class DoNotCopyAttribute: Attribute{} 

// then add this to Odhran's GetMeTheProperties 
bool skip=false; 
foreach (System.Attribute attr in System.Attribute.GetCustomAttributes(sourceProperty)) { 
    if (attr is DoNotCopyAttribute){ skip=true; break; } 
} 
if(skip) continue; 
0
var provider = CodeDomProvider.CreateProvider("c#"); 
var parameters = new CompilerParameters 
{ 
    WarningLevel = 3 // for example, tune how you need 
}; 
var result = provider.CompileAssemblyFromSource(parameters, new string[] { "source" }); 

if (!result.Errors.HasErrors) 
{ 
    var assembly = result.CompiledAssembly; 

    bool containsLocalAppDomain = assembly 
     .GetTypes() 
     .SelectMany(t => t.GetProperties(BindingFlags.Instance | BindingFlags.Public)) 
     .Any(p => p.Name == "YourProperty"); 

    // indeed it's much better not to load compiled assembly in current appDomain, but create a new one 
    var appDomain = AppDomain.CreateDomain("YourNewDomain", null, null); 
    bool containsNewAppDomain = appDomain 
     .GetAssemblies() 
     .SelectMany(a => a 
      .GetTypes() 
      .SelectMany(t => t.GetProperties(BindingFlags.Instance | BindingFlags.Public))) 
     .Any(p => p.Name == "YourProperty"); 

順便說一句,你打算怎麼儘可能的不支持是實現局部性質?