2009-07-29 10 views
41

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

क्या प्रतिबिंब के साथ ऐसा करना संभव है? मुझे पता है कि मैं निजी/आंतरिक सदस्यों तक पहुंच सकता हूं, लेकिन क्या मैं एक आंतरिक कन्स्ट्रक्टर को कॉल कर सकता हूं?

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

प्रदर्शन और "स्थिरता" यहां कोई मुद्दा नहीं है, क्योंकि यह उत्पादन कोड नहीं है।

संपादित करें: बस स्पष्टीकरण के रूप में: दुख की बात है, मैं अन्य विधानसभा पर नियंत्रण नहीं है और यह स्रोत कोड, मैं केवल समझने के लिए के रूप में यह प्रलेखन न के बराबर के बगल में है यह ऐसे कार्य करता कोशिश कर रहा है की जरूरत नहीं है, लेकिन मुझे इसके साथ इंटरफेस करना है।

उत्तर

28

एक FormatterServices.GetUninitializedObject विधि मौजूद है (नाम स्थान: System.Runtime.Serialization), यह माना जाता है कि कोई कंस्ट्रक्टर्स कहता है, यदि आप वास्तव में है कि दृष्टिकोण की कोशिश करना चाहते हैं।

+3

यह और Type.GetField()/FieldInfo.SetValue ने मेरी समस्या हल की। ​​ –

72

कॉलिंग असेंबली को "मित्र" असेंबली के रूप में नामित करने का एक विकल्प होगा।

सीधे शब्दों में आंतरिक निर्माता युक्त विधानसभा की AssemblyInfo.cs फ़ाइल से जोड़ें:

[assembly: InternalsVisibleTo("Calling.Assembly")] 

आप विधानसभा के लिए पहुँच नहीं है, तो आप भी निर्माता सीधे कॉल कर सकते हैं (का उपयोग करते हुए प्रतिबिंब):

MyClass obj = (MyClass) typeof(MyClass).GetConstructor(
        BindingFlags.NonPublic | BindingFlags.Instance, 
        null, Type.EmptyTypes, null).Invoke(null); 
+0

दुर्भाग्य से मैं दूसरे विधानसभा :( –

+1

मेरा उत्तर संपादित एक समाधान प्रतिबिंब –

+0

का उपयोग कर किसी कारण से शामिल करने के लिए नियंत्रित नहीं करता, GetContructor रिटर्न अशक्त, तब भी जब BindingFlags के साथ प्रयोग। लेकिन आम तौर पर यह एक उपयोगी उत्तर है, तो उस पर +1 करें। –

0

internal मतलब यह नहीं है कि आप इसे का दृष्टांत नहीं कर सकते। इसका मतलब यह है कि एक ही असेंबली के केवल सदस्य ही इसे कॉल कर सकते हैं।

परीक्षण उद्देश्यों के लिए आप आंतरिक परीक्षण तक पहुंचने के साथ-साथ InternalsVisibleTo विशेषता का उपयोग करने के लिए अपनी टेस्ट असेंबली को अनुमति दे सकते हैं। देखें http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

+0

एर .. क्या होगा यदि आप इसे किसी अन्य असेंबली से तुरंत चालू करना चाहते हैं। तो आप नहीं कर सकते .... – cjk

+0

सही, जब तक कि आप InternalsVisibleTo का उपयोग नहीं कर सकते। प्रश्न के अपडेट के साथ ऐसा लगता है, लेकिन यह मूल शब्द से मुझे स्पष्ट नहीं था। –

0

आप अपने स्रोत कोड का विश्लेषण करने के लिए Reflector का उपयोग कर सकते हैं और उस आकृति से आंतरिक कार्य को बाहर कर सकते हैं।

+0

आपके 5 वर्षीय उत्तर के पास उनके प्रश्न से कोई लेना देना नहीं है। lol –

+1

@AdamPlocher - खुद को लॉल करें। ओपी स्पष्ट रूप से कहता है कि "मैं केवल यह समझने की कोशिश करता हूं कि यह कैसे काम करता है"। आईएल से कोड को रिवर्स इंजीनियरिंग, इमो, कोड को समझने का एक बहुत व्यवहार्य तरीका है। मैं कहूंगा कि, कुछ असेंबली के आंतरिक कार्यों को समझने के लिए, रनटाइम में एक उदाहरण को पोक करने की कोशिश करने के बजाय कोड को पढ़ना आसान है। तो मेरा जवाब खड़ा है, नीचे या नहीं। –

+0

और @ एडमप्लोकर: मेरा 5 साल पुराना उत्तर इस प्रश्न के अन्य सभी उत्तरों के जितना पुराना है। अरे, सवाल भी 5 साल का है! तो उसके साथ क्या हो रहा है? –

3

मैंने थोड़ी देर पहले इसी स्थिति का अनुभव किया और एक छोटी उपयोगिता बनाई जिसे मैंने "InternalsVisibleToInjector" कहा। यह लक्ष्य चयन असेंबली के लिए InternalsVisibleTo सूची में जोड़े गए मेरे चयन के असेंबली नाम के साथ अलग-अलग, संशोधित, और पुन: इकट्ठा करने और असेंबली के लिए ILDASM और ILASM का उपयोग करता है। यह मेरी स्थिति में काफी अच्छा काम किया।

मैं उपयोगिता यहाँ के लिए स्रोत कोड (2008 सी # WinForm) पोस्ट किया है:

http://www.schematrix.com/downloads/InternalsVisibleToInjector.zip

यह अगर विधानसभा हस्ताक्षरित किया गया है काम न करें। कृपया सभी उचित सावधानी बरतें (यानी इसका उपयोग करने से पहले असेंबली का बैकअप लें और सुनिश्चित करें कि आप ठोस कानूनी आधार पर हैं।

public static T CreateInstance<T>(params object[] args) 
{ 
    var type = typeof (T); 
    var instance = type.Assembly.CreateInstance(
     type.FullName, false, 
     BindingFlags.Instance | BindingFlags.NonPublic, 
     null, args, null, null); 
    return (T) instance; 
} 

उदाहरण उपयोग (यह एक Kinect एसडीके प्रकार है कि मैं इकाई परीक्षण के लिए बनाने के लिए आवश्यक है):

DiscreteGestureResult a = CreateInstance<DiscreteGestureResult>(false, false, 0.5f); 
13

यह एक विधि this answer से प्राप्त होता है इस पर फिर से, प्रतिबिंब के माध्यम से इसे कैसे बढ़ाया जाए इसका एक उदाहरण यहां दिया गया है:

var args = FormatterServices.GetUninitializedObject(typeof(SizeChangedEventArgs)) as SizeChangedEventArgs; 
Debug.Assert(args != null); 

var field = typeof(SizeChangedEventArgs).GetField("_previousSize", BindingFlags.Instance | BindingFlags.NonPublic); 
Debug.Assert(field != null); 
field.SetValue(args, new Size(0,0)); 
field = typeof(SizeChangedEventArgs).GetField("_element", BindingFlags.Instance | BindingFlags.NonPublic); 
Debug.Assert(field != null); 
field.SetValue(args, GraphicsWrapper); 
field = typeof(RoutedEventArgs).GetField("_source", BindingFlags.Instance | BindingFlags.NonPublic); 
Debug.Assert(field != null); 
field.SetValue(args, GraphicsWrapper); 
field = typeof(RoutedEventArgs).GetField("_routedEvent", BindingFlags.Instance | BindingFlags.NonPublic); 
Debug.Assert(field != null); 
field.SetValue(args, SizeChangedEvent); 

GraphicsWrapper.RaiseEvent(args); 

... जहां वें ई GraphicsWrapper वह डब्ल्यूपीएफ नियंत्रण है जिसे आप चाहते हैं।

1

मामले में किसी को भी ठोकर)

+0

बी/सी टिप्पणी के लिए बेहतर उपयुक्त ... आंतरिक सीटीओ को कॉल करना असंभव है। इसलिए उपर्युक्त उदाहरण। ACCEPTED उत्तर में FormatterServices.GetUninitializedObject() विधि का उपयोग करके, आप इस प्रतिबंध को बाईपास करते हैं। – outbred

+0

क्षमा करें, मैं ध्यान नहीं दे रहा था। +1 –

+0

मैं पुनरीक्षण की सराहना करता हूं, @MartinPrikryl। धन्यवाद! – outbred

1

यदि आप प्रतिबिंब से बचना चाहते हैं, तो आप अभिव्यक्तियों का उपयोग कर सकते हैं। स्ट्रिंग मान के साथ एक निजी कन्स्ट्रक्टर को कॉल करने का एक उदाहरण यहां दिया गया है।

private static Func<string, T> CreateInstanceFunc() 
    { 
     var flags = BindingFlags.NonPublic | BindingFlags.Instance; 
     var ctor = typeof(T).GetConstructors(flags).Single(
      ctors => 
      { 
       var parameters = ctors.GetParameters(); 
       return parameters.Length == 1 && parameters[0].ParameterType == typeof(string); 
      }); 
     var value = Expression.Parameter(typeof(string), "value"); 
     var body = Expression.New(ctor, value); 
     var lambda = Expression.Lambda<Func<string, T>>(body, value); 

     return lambda.Compile(); 
    } 
+2

यह प्रतिबिंब से कैसे बचता है? 'Typeof (टी) .GetConstructors (झंडे) .' – weston

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