2012-02-17 9 views
5

एक विधि DeclarationSyntax ऑब्जेक्ट को देखते हुए मैं विधि के घोषित प्रकार को कैसे ढूंढ सकता हूं?एक विधि का घोषित करने वाला प्रकार ढूंढना

मेरी वास्तविक समस्या यह है कि मुझे यह पता लगाने की आवश्यकता है कि संदर्भित विधि एक इंटरफ़ेस विधि लागू कर रही है या नहीं।

उदाहरण के लिए, अगर मैं निपटान() विधि के लिए एक MethodDeclarationSyntax है, कोड bellow दिया, कैसे निष्कर्ष निकाल सकते हैं यह IDisposable.Dispose के कार्यान्वयन है()?

using System; 
abstract class InterfaceImplementation : IDisposable 
{ 
    public abstract void Dispose(); 
} 

मैं विधि के घोषित प्रकार मिलता है (और प्रकार की जांच) कोई सफलता के साथ करने के लिए कोशिश की है (पैरेंट संपत्ति मुझे InterfaceImplementation वर्ग वापस देता है)।

मैं भी विधि के लिए अर्थ प्रतीक हड़पने की कोशिश की है:

var methodSymbol = (MethodSymbol) semanticModel.GetDeclaredSymbol(methodDeclaration); 

लेकिन कुछ भी है कि मुझे मदद कर सकता है स्पॉट नहीं कर सका।

विचार?

उत्तर

7

एक बार जब आप विधि प्रतीक है, तो आप यदि किसी विशेष विधि एक अंतरफलक लागू कर रहा है पूछ सकते हैं:

इसलिए, यदि आप पता लगाने के लिए कि एक निश्चित MethodSymbol लागू करता IDisposable.Dispose() चाहते हैं, आप की तरह कुछ कर सकता है किसी दिए गए प्रकार के भीतर विधि। कोड काफी सरल है:

MethodSymbol method = ...; 
TypeSymbol type = method.ContainingType; 
MethodSymbol disposeMethod = (MethodSymbol)c.GetSpecialType(SpecialType.System_IDisposable).GetMembers("Dispose").Single(); 
bool isDisposeMethod = method.Equals(type.FindImplementationForInterfaceMember(disposeMethod)); 

यह इस प्रकार है कि निपटान विधि शामिल हो जाती है ध्यान देना महत्वपूर्ण है प्रकार है कि कहा गया है यह IDisposable को लागू करता है। सी # में, एक इंटरफ़ेस विधि को कार्यान्वित करने के लिए एक विधि के लिए संभव है जिसे केवल व्युत्पन्न प्रकार पर बताया गया है। अधिक ठोस रूप से, यदि आपने ऊपर दिए गए कोड पर "IDISposable" को झुकाया है, और एक व्युत्पन्न प्रकार इंटरफेस कार्यान्वयन था जो IDISposable था, तो निपटान() विधि अभी भी इसे कार्यान्वित कर सकती है।

+0

मैं 'बराबर()' के बजाय '==' ऑपरेटर का उपयोग करूंगा, क्योंकि 'FindImplementationForInterfaceMember() '' null' वापस कर सकता है। या कम से कम 'बराबर() 'को दूसरी तरफ लिखें। – svick

+0

@svick: समान आदेशों को स्वैप करने पर अच्छा बिंदु। बराबर का मेरा उपयोग दुर्घटना से नहीं है, क्योंकि हमने रोज़लिन टीम पर एक महत्वपूर्ण आदत विकसित की है: == का उपयोग तब तक ठीक काम करेगा जब तक आप केवल भाषा-विशिष्ट प्रकारों का उपयोग नहीं कर रहे हों। यदि आपके पास दो IMethodSymbols थे, तो आपको * उस मामले में == को अधिभारित नहीं किया जाना चाहिए। –

+0

@Jason मुझे डर है कि यह मेरी मदद नहीं करेगा क्योंकि इसमें मान लिया गया है मुझे पता है कि तरीकों मैं के खिलाफ जांच करने की आवश्यकता है जो ऐसा नहीं है (अपने कोड में, आप एक संदर्भ() विधि प्रतीक फेंक और उस के खिलाफ तुलना करने के लिए हड़पने) कर रहा हूँ। निस्संदेह मैं बेस क्लास/इंटरफेस को बार-बार देख सकता हूं (जब तक मैं ऑब्जेक्ट तक नहीं पहुंच जाता) लेकिन मैं उम्मीद करूंगा कि MethodSymbol क्लास मुझे यह जानकारी सीधे प्रदान कर सकता है। – Vagaus

4

सिंटैक्स प्रकार (जैसे MethodDeclarationSyntax) सिंटैक्टिक स्तर पर केवल संचालित करते हैं। इस स्तर पर, कोई ज्ञान नहीं है कि विधि DisposeIDisposable लागू करती है या नहीं। ऐसा इसलिए है क्योंकि आप अभी तक नहीं जानते कि IDisposable में कौन सी विधियां हैं। और भी, आप यह भी नहीं जानते कि IDisposable मौजूद है, चाहे वह कक्षा या इंटरफ़ेस हो या उसका पूरा नाम क्या हो। (क्या यह System.IDisposable है? या MyNamespace.IDisposable?)

इस तरह की जानकारी प्राप्त करने के लिए, आपको अनुमानित रूप से अर्थात् स्तर पर जाना होगा, जैसा कि आपने अनुमान लगाया था।

मुझे एक विधि से सीधे इंटरफ़ेस तक पहुंचने का कोई तरीका नहीं मिला, जब तक कि यह एक स्पष्ट इंटरफ़ेस कार्यान्वयन नहीं है (संपादित करें: ऐसा इसलिए है क्योंकि यह हमेशा संभव नहीं है, केविन की टिप्पणी देखें)। लेकिन आप किसी विशिष्ट प्रकार से कुछ विशिष्ट इंटरफेस विधि के कार्यान्वयन के लिए प्राप्त कर सकते हैं।

SyntaxTree unit = SyntaxTree.ParseCompilationUnit(code); 

MethodDeclarationSyntax method = …; 

var compilation = Compilation.Create("test") 
    .AddReferences(new AssemblyFileReference(typeof(object).Assembly.Location)) 
    .AddSyntaxTrees(unit); 

SemanticModel model = compilation.GetSemanticModel(unit); 

MethodSymbol methodSymbol = (MethodSymbol)model.GetDeclaredSymbol(method); 

var typeSymbol = methodSymbol.ContainingType; 

var idisposableDisposeSymbol = model.BindExpression(
    0, Syntax.ParseExpression("System.IDisposable.Dispose()")).Symbol; 

var implementation = typeSymbol.FindImplementationForInterfaceMember(
    idisposableDisposeSymbol); 

bool methodImplementsDispose = methodSymbol == implementation; 
+1

कारण से आप यह नहीं कर सकते हैं कि कभी-कभी आप यह नहीं बता सकते हैं। यदि आपके पास 'क्लास बेस {सार्वजनिक शून्य निपटान()} क्लास व्युत्पन्न है: बेस, आईडीस्पोजेबल {}' फिर "निपटान करें" कार्यान्वयन है _if आपके पास Derived_ का एक उदाहरण है, लेकिन यदि आपके पास बेस का उदाहरण नहीं है ... –

+0

हम्म, मुझे एहसास नहीं हुआ कि यह भी संभव है, दिलचस्प है। – svick

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