C # में रनटाइम पर DLL लोड हो रहा है


91

मैं यह पता लगाने की कोशिश कर रहा हूं कि आप C # एप्लिकेशन के अंदर रनटाइम पर एक .dll का आयात और उपयोग कैसे कर सकते हैं। असेंबली का उपयोग करते हुए। LoadFile () मैं dll को लोड करने के लिए अपना कार्यक्रम प्राप्त करने में कामयाब रहा (यह हिस्सा निश्चित रूप से काम कर रहा है क्योंकि मैं कक्षा का नाम ToString () के साथ प्राप्त करने में सक्षम हूं, हालांकि मैं 'आउटपुट' का उपयोग करने में असमर्थ हूं। मेरे कंसोल एप्लिकेशन के अंदर की विधि। मैं -dll को संकलित कर रहा हूं और फिर इसे मेरे कंसोल प्रोजेक्ट में स्थानांतरित कर रहा हूं। क्या CreateInstance और फिर विधियों का उपयोग करने में सक्षम होने के बीच एक अतिरिक्त कदम है?

यह मेरी DLL में कक्षा है:

namespace DLL
{
    using System;

    public class Class1
    {
        public void Output(string s)
        {
            Console.WriteLine(s);
        }
    }
}

और यहां वह एप्लिकेशन है जिसे मैं DLL लोड करना चाहता हूं

namespace ConsoleApplication1
{
    using System;
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

            foreach(Type type in DLL.GetExportedTypes())
            {
                var c = Activator.CreateInstance(type);
                c.Output(@"Hello");
            }

            Console.ReadLine();
        }
    }
}

जवाबों:


128

सदस्यों को सी # से सीधे कॉल करने के लिए संकलित समय पर पुन: प्रयोज्य होना चाहिए। अन्यथा आपको प्रतिबिंब या गतिशील वस्तुओं का उपयोग करना चाहिए।

प्रतिबिंब

namespace ConsoleApplication1
{
    using System;
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

            foreach(Type type in DLL.GetExportedTypes())
            {
                var c = Activator.CreateInstance(type);
                type.InvokeMember("Output", BindingFlags.InvokeMethod, null, c, new object[] {@"Hello"});
            }

            Console.ReadLine();
        }
    }
}

डायनामिक (.NET 4.0)

namespace ConsoleApplication1
{
    using System;
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

            foreach(Type type in DLL.GetExportedTypes())
            {
                dynamic c = Activator.CreateInstance(type);
                c.Output(@"Hello");
            }

            Console.ReadLine();
        }
    }
}

12
ध्यान दें कि यह Outputविधानसभा में हर प्रकार पर कॉल करने की कोशिश करता है , जो संभवतः "सही" वर्ग पाए जाने से पहले फेंक देगा ...
रीड कोप्सी

1
@ReedCopsey, सहमत, लेकिन उनके सरल उदाहरण के लिए, उनका प्रकार केवल एक ही दिखाई देता है। "एक विधानसभा के बाहर दिखाई देने वाले एकमात्र प्रकार सार्वजनिक प्रकार हैं और सार्वजनिक प्रकार अन्य सार्वजनिक प्रकारों के भीतर होते हैं।" एक गैर-तुच्छ उदाहरण के लिए, जाहिर है कि यह एक मुद्दा होगा ...
डार्क फाल्कन

1
दो उदाहरणों के साथ नीट! :)
नील्स एबल्डगार्ड

22
यही कारण है कि इंटरफेस अक्सर उपयोग किया जाता है और आप फीचर डिटेक्शन जैसे कि कर सकते हैं IDog dog = someInstance as IDog;और यदि यह शून्य नहीं है तो परीक्षण करें। क्लाइंट्स द्वारा साझा किए गए एक सामान्य DLL में अपना इंटरफेस रखें, और किसी भी प्लगइन को जो गतिशील रूप से लोड किया जाएगा, उस इंटरफ़ेस को लागू करना होगा। यह तब आपको अपने क्लाइंट को IDog इंटरफ़ेस के खिलाफ कोड करने देगा और डायनामिक उपयोग के बजाय संकलन समय पर intellisense + मजबूत प्रकार की जाँच करेगा।
एरोनल्स

1
@ Tarek.Mh: इसके लिए एक संकलन-समय पर निर्भरता की आवश्यकता होगी Class1। उस बिंदु पर आप बस उपयोग कर सकते हैं new Class1()। पूछने वाले ने स्पष्ट रूप से एक रनटाइम निर्भरता निर्दिष्ट की। dynamicकार्यक्रम को Class1सभी पर एक संकलन-समय की निर्भरता की आवश्यकता नहीं है ।
अंधेरा फाल्कन

39

अभी, आप विधानसभा में परिभाषित हर प्रकार का एक उदाहरण बना रहे हैं । Class1विधि को कॉल करने के लिए आपको केवल एक ही उदाहरण बनाने की आवश्यकता है :

class Program
{
    static void Main(string[] args)
    {
        var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

        var theType = DLL.GetType("DLL.Class1");
        var c = Activator.CreateInstance(theType);
        var method = theType.GetMethod("Output");
        method.Invoke(c, new object[]{@"Hello"});

        Console.ReadLine();
    }
}

19

आपको उस प्रकार का एक उदाहरण बनाने की आवश्यकता है जो Outputविधि को उजागर करता है:

static void Main(string[] args)
    {
        var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

        var class1Type = DLL.GetType("DLL.Class1");

        //Now you can use reflection or dynamic to call the method. I will show you the dynamic way

        dynamic c = Activator.CreateInstance(class1Type);
        c.Output(@"Hello");

        Console.ReadLine();
     }

बहुत बहुत धन्यवाद - यह वही है जिसकी मुझे तलाश है। मुझे विश्वास नहीं हो रहा है कि यह अन्य उत्तरों की तुलना में अधिक रेटेड नहीं है, क्योंकि यह डायनामिक कीवर्ड का उपयोग दिखाता है।
स्किप्पॉपी

आह, अब मैं देख रहा हूँ यह DarkFalcon के जवाब में भी था। तुम्हारा छोटा था और यह देखना आसान बना दिया, हालांकि। :)
स्किप्पॉपी

0

Activator.CreateInstance() एक वस्तु देता है, जिसमें आउटपुट विधि नहीं है।

ऐसा लगता है कि आप गतिशील प्रोग्रामिंग भाषाओं से आते हैं? C # निश्चित रूप से ऐसा नहीं है, और आप जो करने की कोशिश कर रहे हैं वह मुश्किल होगा।

चूंकि आप किसी विशिष्ट स्थान से एक विशिष्ट dll लोड कर रहे हैं, हो सकता है कि आप इसे अपने कंसोल एप्लिकेशन के संदर्भ के रूप में जोड़ना चाहते हों?

यदि आप पूरी तरह से असेंबली को लोड करना चाहते हैं Assembly.Load, तो आपको किसी भी सदस्य को कॉल करने के लिए प्रतिबिंब से गुजरना होगाc

कुछ ऐसा type.GetMethod("Output").Invoke(c, null);करना चाहिए।


0
foreach (var f in Directory.GetFiles(".", "*.dll"))
            Assembly.LoadFrom(f);

जो आपके निष्पादन योग्य फ़ोल्डर में मौजूद सभी DLL को लोड करता है।

मेरे मामले में मैं Reflectionएक कक्षा के सभी उपवर्गों को खोजने के लिए उपयोग करने की कोशिश कर रहा था , यहां तक ​​कि अन्य DLL में भी। यह काम किया है, लेकिन मुझे यकीन नहीं है कि यह करने का सबसे अच्छा तरीका है।

संपादित करें: मैंने इसे समयबद्ध किया है, और यह केवल उन्हें पहली बार लोड करने के लिए लगता है।

Stopwatch stopwatch = new Stopwatch();
for (int i = 0; i < 4; i++)
{
    stopwatch.Restart();
    foreach (var f in Directory.GetFiles(".", "*.dll"))
        Assembly.LoadFrom(f);
    stopwatch.Stop();
    Console.WriteLine(stopwatch.ElapsedMilliseconds);
}

आउटपुट: 34 0 0 0

तो कोई संभावित रूप से किसी मामले में रिफ्लेक्शन से पहले उस कोड को चला सकता है।


-1

यह इतना मुश्किल नहीं है।

आप लोड की गई वस्तु के उपलब्ध कार्यों का निरीक्षण कर सकते हैं, और यदि आप किसी ऐसे व्यक्ति को ढूंढते हैं जिसे आप नाम से देख रहे हैं, तो उसके अपेक्षित पार्म्स, यदि कोई हो यदि यह वह कॉल है जिसे आप ढूंढने का प्रयास कर रहे हैं, तो इसे MethodInfo ऑब्जेक्ट के इनवोक विधि का उपयोग करके कॉल करें।

एक अन्य विकल्प केवल अपनी बाहरी वस्तुओं को एक इंटरफेस में बनाना है, और उस ऑब्जेक्ट पर लोड की गई वस्तु को डालना है। सफल होने पर, फ़ंक्शन को मूल रूप से कॉल करें।

यह बहुत आसान सामान है।


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

10
मुझे लगता है कि डाउनवोट्स को उदाहरणों और संघनक टोन की कमी के साथ करना होगा ... ऐसा लगता है जैसे आपके पास पूर्ण उत्तर के लिए आधार है, लेकिन अधिक विवरण में संपादित करने से डरो मत :)
छाया

1
यह "यह बहुत सरल सामान है" कहने के लिए सिर्फ असभ्य है, और यही कारण है कि आपको डाउनवोट मिला है।
एबीपर्सन

1
मैं कठोर या कृपालु नहीं हो रहा था .... 6 साल पहले। टोन पाठ के माध्यम से नहीं आता है, स्पष्ट रूप से। यह वास्तव में बहुत हल्का दिल होने का मतलब था ... मैं भी वास्तव में ऐसा महसूस करता हूं कि मेरे पास उन सभी वर्षों में एक कोड नमूने का लिंक था, और मुझे नहीं पता कि यह कहां गया (यह मानते हुए कि वास्तव में ऐसा था जैसे मैं याद कर रहा हूं )। : \
Chrish

मुझे नहीं पता कि MethodInfo कैसे काम करता है लेकिन यह मूल्यवान लगता है। मैं कहूंगा कि आपके उत्तर में वर्तमान स्वीकृत एक से बेहतर होने की संभावना है, लेकिन इसे पूरा करने की आवश्यकता होगी। यदि आप कभी भी इसके आसपास पहुंचते हैं तो इसकी सराहना की जाएगी। यदि हां, तो कृपया एक कोड नमूने से लिंक न करें। ये भविष्य में टूट सकते हैं। नमूना को स्वयं प्रदान करना सबसे अच्छा है, संभवतः किसी स्रोत के लिए लिंक या निरंतर पढ़ने के लिए अतिरिक्त जानकारी।
स्पेगेटीकेक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.