2010-06-10 11 views
6

से संपत्ति नाम निकालने के लिए मैं एक C# फ़ाइल को पार्स करना चाहता हूं। एकमात्र चीज जो मैं चाहता हूं वह यह निर्धारित करना है कि इसमें एक विशिष्ट नाम वाली संपत्ति है या नहीं; बस एक साधारण सच/झूठी प्रतिक्रिया। या बल्कि, के बाद से मैं एक समय में एक से अधिक संपत्ति के लिए जाँच था, संपत्ति नामों की सूची निकालने उपयोगीसी # स्रोत फ़ाइल

मैंने सोचा था कि मैं CodeDomProvider कार्यक्षमता (च # उदाहरण) का उपयोग कर एक सुरुचिपूर्ण समाधान बना सकते हैं हो सकता है:

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

दुर्भाग्यवश, Parse फ़ंक्शन CSharpCodeProvider के लिए लागू नहीं किया गया है। क्या स्रोत फ़ाइल से CodeCompileUnit प्राप्त करने का कोई तरीका है? या कोई और सुरुचिपूर्ण तरीका है? (मुझे इस पर नियमित अभिव्यक्ति से बचने की उम्मीद थी)?

संपादित करें: मैं स्वचालित कोड पीढ़ी के लिए इसका उपयोग करने जा रहा हूं। असल में, मैं फ़ाइल xyz.partial.cs में आंशिक वर्ग उत्पन्न करने जा रहा हूं। यह एक कंकाल संपत्ति उत्पन्न करेगा। लेकिन अगर मैं किसी संपत्ति के कार्यान्वयन को बदलना चाहता हूं, तो मैं उस संपत्ति को काट दूंगा और उसे हाथ में कोडित xyz.cs. में पेस्ट करूँगा। जेनरेटेड क्लास को पुनर्निर्मित करते समय, मैं चाहता हूं कि यह उत्पन्न गुणों को छोड़ दें जो मैं हाथ से कोडित फ़ाइल में स्थानांतरित हो गया हूं।

इसलिए, प्रतिबिंब प्रश्न से बाहर है, क्योंकि प्रतिबिंब मुझे बताएगा कि संपत्ति वास्तव में मौजूद है, लेकिन यदि यह एक या दूसरी फ़ाइल में परिभाषित नहीं है।

+0

फिर भी, मैं ओपन एक्सप्रेसो पॉप करने के लिए खुजली कर रहा हूं और इसे एक शॉट देता हूं। मैं नियमित रूप से कुछ भी अभिव्यक्ति कर सकता हूं और 'शक्ति में मुझे शक्ति नहीं रोक सकती है। –

+1

क्या आपने स्रोत के संकलित संस्करण पर प्रतिबिंब पर विचार किया था? या यह एक विकल्प नहीं है? निश्चित नहीं है कि प्रतिबिंब संपत्ति नाम प्रदान करता है हालांकि। –

+0

@ मॉरॉन - यह वास्तव में बहुत अच्छी तरह से काम करना चाहिए। – ChaosPandion

उत्तर

0

कभी कभी रेगुलर एक्सप्रेशन से केवल सुरुचिपूर्ण समाधान है। यह वही होना चाहिए जो आप खोज रहे हैं। यह आप कोड फ़ाइल में हर संपत्ति के नाम दे देंगे, और ज्यादा कुछ नहीं:

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

यह टिप्पणी या तार में इसी तरह के कोड से मेल नहीं खाएगी और केवल एक छोटा सा संशोधन की जरूरत है संपत्ति का प्रकार वापस जाने के लिए। नाम कैप्चर \ 1 में दिखाई देता है, लेकिन यदि कोई सही मिलान नहीं है तो रिक्त होगा।

+2

आप इसे "सुरुचिपूर्ण" कहते हैं? "कुछ लोग, जब किसी समस्या का सामना करते हैं, तो सोचें" मुझे पता है, मैं नियमित अभिव्यक्तियों का उपयोग करूंगा। "अब उनके पास दो समस्याएं हैं" –

+0

आप क्या उपयोग करेंगे? नेस्टेड loops और substrings? जगह से बाहर एक नंबर और आप समस्याओं का एक अप्रत्याशित विस्फोट है। रेगेक्स कभी मेरे लिए कोई समस्या नहीं रही है, और अक्सर कोड की केवल एक पंक्ति में काम किया जाता है। अधिक कुशल – Patrick

+0

मुझे एहसास हुआ कि मुझे शायद रेगेक्स का उपयोग करने की आवश्यकता है, और यह मुझे शुरू कर दिया है, लेकिन कुछ चीजें हैं जो इससे मेल नहीं खाती हैं: सामान्य या शून्य प्रकार वाले गुण (क्योंकि प्रकार का नाम किसी चरित्र में समाप्त नहीं होता है, लेकिन एक? या ए>), और यह ऑटो गुणों (स्वचालित बैकिंग फ़ील्ड वाले गुण) से मेल नहीं खाता है – Pete

1

संपादित 2: अतिरिक्त जानकारी के आधार पर, मैं कहूंगा कि आप हाथ कोडित वर्ग को संकलित करने और फिर उस वर्ग को प्रतिबिंबित करने के लिए सबसे अच्छे हैं। फिर आप आंशिक वर्ग फ़ाइल के लिए कोड उत्पन्न कर सकते हैं।

संपादित करें: मैंने कुछ और शोध किया है और ऐसा लगता है कि आप भाग्य से बाहर हैं। कोडडॉम का उपयोग कोड को पार्स करने के लिए नहीं किया जा सकता है। 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

ऐसा लगता है कि पार्स विधि सभी CodeDomProvider कक्षाओं द्वारा लागू नहीं की गई है। मूल प्रश्न यह ध्वनि बनाता है जैसे इसे सी # द्वारा लागू नहीं किया गया है। किसी को भी निश्चित रूप से पता है? –

+0

वे मुझे लगता है कि रनटाइम पर लागू कर रहे हैं। क्या आपने वास्तव में कोड चलाने की कोशिश की है? जब तक यह रनटाइम पर अपवाद फेंकता है, तो मेरा सुझाव है कि आप इसे आज़माएं। –

+0

इसी तरह मैंने इसे शुरू किया। यह एक ही परिणाम देता है, NotImplementedException। CodeDomProvider.CreateProvider ("CSharp") बस एक CSharpCodeProvider देता है। – Pete

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

+0

क्षमा करें ... प्रश्न का गलत व्याख्या किया। – Odhran

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"); 

Btw, कैसे आप जहाँ तक समर्थित नहीं हैं के रूप में आंशिक गुण लागू करने के लिए जा रहे हैं?

संबंधित मुद्दे