2009-05-28 11 views
72

से आंतरिक वर्ग तक पहुँचने के लिए एक विधानसभा जो मैं संशोधित नहीं कर सकते (विक्रेता की आपूर्ति) जो कि एक वस्तु प्रकार देने वाला विधि है, लेकिन वास्तव में एक आंतरिक प्रकार की है बीत रहा है।सी # - कैसे बाहरी विधानसभा

मैं अपनी असेंबली से ऑब्जेक्ट के फ़ील्ड और/या विधियों तक कैसे पहुंच सकता हूं?

ध्यान रखें कि मैं विक्रेता द्वारा प्रदान की गई असेंबली को संशोधित नहीं कर सकता।

संक्षेप में, यहाँ मैं क्या है:

विक्रेता से:

internal class InternalClass 
    public string test; 
end class 

public class Vendor 
    private InternalClass _internal; 
    public object Tag {get{return _internal;}} 
end class 

मेरी विधानसभा से विक्रेता विधानसभा का उपयोग कर।

public class MyClass 
{ 
    public void AccessTest() 
    { 
    Vendor vendor = new Vendor(); 
    object value = vendor.Tag; 
    // Here I want to access InternalClass.test 
    } 
} 

उत्तर

70

प्रकार तक पहुंच के बिना (और कोई "आंतरिक दृश्यमान" आदि) आपको प्रतिबिंब का उपयोग करना होगा। लेकिन एक बेहतर सवाल यह होगा: क्या आप इस डेटा तक पहुंच रहे हैं? यह सार्वजनिक प्रकार के अनुबंध का हिस्सा नहीं है ... यह मुझे लगता है जैसे इसे एक अपारदर्शी वस्तु के रूप में माना जाना है (उनके उद्देश्यों के लिए, आपका नहीं)।

आपने इसे सार्वजनिक उदाहरण फ़ील्ड के रूप में वर्णित किया है; प्रतिबिंब के माध्यम से इस पाने के लिए:

object obj = ... 
string value = (string)obj.GetType().GetField("test").GetValue(obj); 

तो यह वास्तव में एक संपत्ति (नहीं एक क्षेत्र) है:

string value = (string)obj.GetType().GetProperty("test").GetValue(obj,null); 

यदि यह गैर सरकारी है, तो आप GetField की BindingFlags अधिभार का उपयोग करना होगा/GetProperty

महत्वपूर्ण तरफ: इस तरह के प्रतिबिंब से सावधान रहें; कार्यान्वयन अगले संस्करण (आपके कोड को तोड़ने) में बदल सकता है, या इसे obfuscated (अपना कोड तोड़ना) हो सकता है, या आपके पास पर्याप्त "ट्रस्ट" (अपना कोड तोड़ना) नहीं हो सकता है। क्या आप पैटर्न खोज रहे हैं?

+1

Wooo .. 2 मिनट! वो बहुत नजदीक था! अच्छी तरह से मार्क (हमेशा के रूप में) कहा। : डी – Galilyou

+0

ग्रेट! यह काम करता है। मैंने सोचा कि मैं इस तरह से आंतरिक तक नहीं पहुंच सका ... बहुत बहुत धन्यवाद –

+0

मार्क मुझे आश्चर्य है ... निजी क्षेत्रों/संपत्तियों तक पहुंच बनाना संभव है, लेकिन सही प्रकार का उपयोग करके GetValue द्वारा लौटाई गई वस्तु को कास्ट करने का कोई तरीका है? – codingadventures

-3

अच्छा, आप नहीं कर सकते। आंतरिक कक्षाएं उनकी असेंबली के बाहर दिखाई नहीं दे सकती हैं, इसलिए इसे सीधे एक्सेस करने का कोई स्पष्ट तरीका नहीं है - निश्चित रूप से AFAIK। एकमात्र तरीका प्रतिबिंब के माध्यम से रनटाइम देर से बाध्यकारी का उपयोग करना है, फिर आप आंतरिक वर्ग से अप्रत्यक्ष रूप से विधियों और गुणों का आह्वान कर सकते हैं।

+0

zonkflut के समाधान ने पिछले – phlip

+0

में मेरे लिए काम किया है, हालांकि यह कॉल किया गया असेंबली – phlip

+4

संपादित करने पर निर्भर करता है, आप प्रतिबिंब –

3

प्रतिबिंब।

using System.Reflection; 

Vendor vendor = new Vendor(); 
object tag = vendor.Tag; 

Type tagt = tag.GetType(); 
FieldInfo field = tagt.GetField("test"); 

string value = field.GetValue(tag); 

बुद्धिमानी से शक्ति का उपयोग करें। त्रुटि जांचना मत भूलना। :)

171

मुझे केवल एक मामला दिखाई देता है कि आप अपने आंतरिक सदस्यों को किसी अन्य असेंबली में एक्सपोजर करने की अनुमति देंगे और यह परीक्षण उद्देश्यों के लिए है।

कह internals के लिए "मित्र" विधानसभाओं उपयोग की अनुमति के लिए एक रास्ता है कि वहाँ:

परियोजना आप प्रत्येक विधानसभा के लिए एक पंक्ति जोड़ें की AssemblyInfo.cs फ़ाइल में।

[assembly: InternalsVisibleTo("name of assembly here")] 

यह जानकारी उपलब्ध here.

आशा इस मदद करता है।

+1

के साथ कुछ भी कॉल कर सकते हैं बस आज मैं एक स्क्रीनकैस्ट से संपर्क कर रहा था और किसी दिए गए असेंबली के आंतरिक सदस्यों को उजागर करने के बारे में सुना तो एक और (परीक्षण असेंबली) तक पहुंच है, लेकिन उसे नहीं पता था कि इसे कैसे किया जाए। धन्यवाद! –

+3

वोट दें क्योंकि यह मेरे लिए उपयोगी जानकारी थी ... हालांकि यह प्रश्न का उत्तर नहीं हो सकता है :- डी – yeyeyerman

+4

सवाल यह विशेष रूप से कहता है कि पार्टनर असेंबली को संशोधित नहीं किया जा सका। नीचे वोट करें। – danielpops

3

मैं एक बिंदु पर बहस करना चाहता हूं - कि आप मूल असेंबली में वृद्धि नहीं कर सकते - मोनो। सेसिल का उपयोग करके आप [InternalsVisibleTo(...)] को 3 असेंबली में इंजेक्ट कर सकते हैं। ध्यान दें कि कानूनी प्रभाव हो सकते हैं - आप 3 खाली असेंबली और तकनीकी प्रभावों के साथ गड़बड़ कर रहे हैं - यदि असेंबली के पास मजबूत नाम है तो आपको इसे अलग करने या इसे अलग-अलग कुंजी के साथ पुनः हस्ताक्षर करने की आवश्यकता है।

Install-Package Mono.Cecil 

और कोड की तरह:

static readonly string[] s_toInject = { 
    // alternatively "MyAssembly, PublicKey=0024000004800000... etc." 
    "MyAssembly" 
}; 

static void Main(string[] args) { 
    const string THIRD_PARTY_ASSEMBLY_PATH = @"c:\folder\ThirdPartyAssembly.dll"; 

    var parameters = new ReaderParameters(); 
    var asm = ModuleDefinition.ReadModule(INPUT_PATH, parameters); 
    foreach (var toInject in s_toInject) { 
    var ca = new CustomAttribute(
     asm.Import(typeof(InternalsVisibleToAttribute).GetConstructor(new[] { 
         typeof(string)}))); 
    ca.ConstructorArguments.Add(new CustomAttributeArgument(asm.TypeSystem.String, toInject)); 
    asm.Assembly.CustomAttributes.Add(ca); 
    } 
    asm.Write(@"c:\folder-modified\ThirdPartyAssembly.dll"); 
    // note if the assembly is strongly-signed you need to resign it like 
    // asm.Write(@"c:\folder-modified\ThirdPartyAssembly.dll", new WriterParameters { 
    // StrongNameKeyPair = new StrongNameKeyPair(File.ReadAllBytes(@"c:\MyKey.snk")) 
    // }); 
} 
+0

मेरे लिए, संशोधित नहीं किया जा सकता है इसका मतलब है कि यह एक नाजेट से आता है और मैं संशोधनों के साथ स्थानीय न्यूजेट बनाना और प्रबंधित नहीं करना चाहता हूं। इसके अलावा, कुछ लोगों के लिए, एक मजबूत नाम का नुकसान मायने रखता है। लेकिन यह एक दिलचस्प बात है। – binki