मैं बाहरी विधानसभा से आंतरिक वर्ग तक कैसे पहुंच सकता हूं?


97

असेंबली होना, जिसे मैं संशोधित नहीं कर सकता (विक्रेता-आपूर्ति) जिसके पास एक वस्तु प्रकार लौटाने की एक विधि है लेकिन वास्तव में एक आंतरिक प्रकार है।

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

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

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

विक्रेता से:

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
  }
}

जवाबों:


83

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

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

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

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

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

यदि यह गैर-सार्वजनिक है, तो आपको / के BindingFlagsअधिभार का उपयोग करना होगा ।GetFieldGetProperty

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


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

1
@GiovanniCampo यदि आप सांख्यिकीय रूप से जानते हैं कि प्रकार क्या है: निश्चित - बस कास्ट। आप प्रकार स्थिर नहीं जानते हैं - यह स्पष्ट नहीं है क्या होगा यहां तक कि इस मतलब
मार्क Gravell

उन लोगों के बारे में जो इंटर्नल्स के रूप में चीजों को प्रकाशित करते हैं जो वास्तव में सार्वजनिक एपीआई का हिस्सा हैं? या उन्होंने इस्तेमाल किया InternalsVisibleToलेकिन अपनी विधानसभा को शामिल नहीं किया? यदि प्रतीक वास्तव में छिपा नहीं है, तो यह ABI का हिस्सा है।
बिंकी

208

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

यह कहना कि "मित्र" असेंबली को इंटर्नल तक पहुंचने की अनुमति देने का एक तरीका है:

असेंबली के Info.cs फ़ाइल में आप प्रत्येक असेंबली के लिए एक पंक्ति जोड़ते हैं।

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

यह जानकारी यहाँ उपलब्ध है।

उम्मीद है की यह मदद करेगा।


परीक्षण उद्देश्यों के मामले पर विस्तार करना। कोई भी परिदृश्य जहाँ आपने अलग-अलग संदर्भों में कपल्स को जोड़ा है। उदाहरण के लिए, एकता में, आपके पास एक रनटाइम असेंबली, एक टेस्ट असेंबली और एक संपादक असेंबली हो सकती है। परीक्षण और संपादक असेंबलियों को रनटाइम इंटर्नल्स दिखाई देनी चाहिए।
स्टीव बुज़ोनास

3
मुझे नहीं लगता कि यह उत्तर मदद करता है - ओपी का कहना है कि वह विक्रेता की विधानसभा को संशोधित नहीं कर सकता है, और यह जवाब विक्रेता की परियोजना के
साइमन ग्रीन

6

मैं एक बिंदु पर बहस करना चाहूंगा - कि आप मूल असेंबली में वृद्धि नहीं कर सकते - Mono.Cecil का उपयोग करके आप 3 [InternalsVisibleTo(...)]सिट असेंबली में इंजेक्ट कर सकते हैं । ध्यान दें कि कानूनी निहितार्थ हो सकते हैं - आप 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"))
   // });
}

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

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

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


-2

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


5
आप परावर्तन के साथ कुछ भी कह सकते हैं
श्रीहिंश - मार्टिन हिंसेलवुड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.