[C# i dll] Utworzenie obiektu z dynamicznie ładowanej dllki

0

Mam taką klasę:

    public class MathClass
    {
        public MathClass()
        {
            a = 0;
            b = 0;
        }

        private int a;
        private int b;

        public int A
        {
            get { return a; }
            set { a = value; }
        }

        public int B
        {
            get { return b; }
            set { b = value; }
        }

        public int Sum()
        {
            return a + b;
        }

        public int Difference()
        {
            return a - b;
        }
    }

Zbudowałem sobie plik dll z tą klasą i teraz chciałbym tej klasy używać w drugim programie. Założenie jest jednak takie, że z góry nie będę wiedział jakie dllki (pluginy) znajdą się w folderze z programem docelowym i w zależności od tego, mój program ma tworzyć odpowiednie obiekty i działać na nich. Na razie mam coś takiego:

        static void Main(string[] args)
        {
            DirectoryInfo di = new DirectoryInfo("DLL\\"); //folder z dllkami
            FileInfo[] dllFiles = di.GetFiles("*.dll"); //łapiemy wszystkie ewentualne dllki w folderze
            Assembly assembly;
            Object ob;
            FileInfo fi = dllFiles[0]; //bierzemy pierwszą dllkę
            Console.WriteLine(fi.Name);
            assembly = Assembly.LoadFrom(fi.FullName); //ładujemy assembly
            Type mathType = assembly.GetTypes()[0]; //łapiemy pierwszy typ z assembly
            Console.WriteLine(mathType.Name);
            ob = Activator.CreateInstance(mathType); //tworzymy obiekt złapanego typu
            MethodInfo mi = mathType.GetMethod("Sum"); //łapiemy metodę Sum
            Console.WriteLine(mi.Name);
            Object result = mi.Invoke(ob, null); //wywołujemy metodę Su,
            Console.WriteLine(result.ToString());
            PropertyInfo piA = mathType.GetProperty("A"); //łapiemy properties
            PropertyInfo piB = mathType.GetProperty("B");
            Console.WriteLine(piA.Name + " " + piB.Name);
            piA.SetValue(ob, 2, null); //ustawiamy properties
            piB.SetValue(ob, 3, null);
            result = mi.Invoke(ob, null); //jeszcze raz wywołujemy metodę Sum
            Console.WriteLine(result.ToString()); //i widzimy, że wynik się zmienił ;)
            Console.ReadKey();
        }

To wszystko działa. Ale moje pytanie dotyczy tego, czy da się to rozwiązać w jakiś lepszy sposób? Na przykład czy byłaby możliwość uzyskania obiektu MathClass i działania na nim, jak na obiekcie z biblioteki statycznie dodanej poprzez references (np. mathObject.Sum() )?

0

Stwórz oddzielną bibliotekę, w której zamieścisz interfejsy, np. IMath. Taki interfejs będzie deklarował odpowiednie metody. Referencję do tej biblioteki dodasz zarówno do swojego programu jak i biblioteki z właściwą klasą.

Wtedy w głównym programie, przeszukasz wszystkie typy i stworzysz obiekt tego, który dziedziczy po IMath (Type.IsAssignable).

Ewentualnie druga opcja to dołączenie referencji do głównego programu i ew. łapanie wyjątków rzucanych przez framework w wypadku nieznalezienia biblioteki, ale to wydaje mi się, że o wiele lepszym rozwiązaniem będzie ta opcja z interfejsami.

0

Skoro wiesz, jakie operacje sa w bibliotece i chcesz odnosic sie konkretnie do nich, to po co Ci linkowanie dynamiczne?

0

Ok, teraz mam taki interfejs:

namespace IMath
{
    public interface IMath
    {
        int Sum();
        int Difference();
    }
}

taką dynamicznie ładowaną dllkę:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DLLTestLibrary
{
    public class MathClass : IMath.IMath
    {
        public MathClass()
        {
            a = 0;
            b = 0;
        }

        private int a;
        private int b;

        public int A
        {
            get { return a; }
            set { a = value; }
        }

        public int B
        {
            get { return b; }
            set { b = value; }
        }

        public int Sum()
        {
            return a + b;
        }

        public int Difference()
        {
            return a - b;
        }
    }
}

i program główny:

using System;
using System.IO;
using System.Reflection;

namespace DLLTest
{
    class Program
    {
        static void Main(string[] args)
        {
            DirectoryInfo di = new DirectoryInfo("DLL\\"); //folder z dllkami
            FileInfo[] dllFiles = di.GetFiles("*.dll"); //łapiemy wszystkie ewentualne dllki w folderze
            foreach (FileInfo info in dllFiles)
            {
                Assembly assembly;
                Object ob;
                Console.WriteLine(info.Name);
                assembly = Assembly.LoadFrom(info.FullName); //ładujemy assembly
                Type[] mathTypes = assembly.GetTypes(); //łapiemy pierwszy typ z assembly
                foreach (Type type in mathTypes)
                {
                    if (type.IsAssignableFrom(typeof(IMath.IMath)))
                    {
                        Console.WriteLine(type.Name);
                        ob = Activator.CreateInstance(type); //tworzymy obiekt złapanego typu
                        MethodInfo mi = type.GetMethod("Sum"); //łapiemy metodę Sum
                        Console.WriteLine(mi.Name);
                        Object result = mi.Invoke(ob, null); //wywołujemy metodę Su,
                        Console.WriteLine(result.ToString());
                        PropertyInfo piA = type.GetProperty("A"); //łapiemy properties
                        PropertyInfo piB = type.GetProperty("B");
                        Console.WriteLine(piA.Name + " " + piB.Name);
                        piA.SetValue(ob, 2, null); //ustawiamy properties
                        piB.SetValue(ob, 3, null);
                        result = mi.Invoke(ob, null); //jeszcze raz wywołujemy metodę Sum
                        Console.WriteLine(result.ToString()); //i widzimy, że wynik się zmienił ;)   
                    }
                }
            }
            Console.ReadKey();
        }
    }
}

Dodałem również referencję w odpowiednich miejscach. Całość jednak nie działa... Co jest nie tak?

Szczawik napisał(a)

Skoro wiesz, jakie operacje sa w bibliotece i chcesz odnosic sie konkretnie do nich, to po co Ci linkowanie dynamiczne?

Mam program, który obsługuje moduły dotyczące sprzedaży, różnych typów rzeczy. Chciałbym, żeby każdy typ przedmiotu był osobną dllką wrzucaną do określonego folderu i wtedy program ładując te dllki, wiedziałby jakie typy przedmiotów ma obsługiwać. Co więcej, dodanie obsługi kolejnego typu będzie się sprowadzało do wrzucenia kolejnej dllki do folderu.

//polecam używanie składni <code class="csharp">...</code> - czytelniejszy kod - M

0

a nie lepiej bedzie wrzucic taki obiekt po prostu do listy ? i operowac na nim ?
Ja zrobilem cos takiego i dziala:

files = Directory.GetFiles(folder,"*.dll");
            Assembly asm ;
            pluginy = new List<IPlugin.IPlugin>(); //lista zawierajace dll implementujace interfejs IPlugin

            foreach (string file in files)
            {
                asm = Assembly.LoadFile(file);
                foreach (Type type in asm.GetTypes())
                {
                    if (typeof(IPlugin.IPlugin).IsAssignableFrom(type))
                    {
                        IPlugin.IPlugin plugin = Activator.CreateInstance(type) as IPlugin.IPlugin;
                        pluginy.Add(plugin); //dodajemy taki object do listy

                    }
                }
            }

        

                listBox1.DataSource = pluginy; // mozemy powiazac np z listboxem i np pozniej w
//programie uzyc o tak:

private void listBox1_MouseClick(object sender, MouseEventArgs e)
        {
            IPlugin.IPlugin plug = this.listBox1.SelectedItem as IPlugin.IPlugin;

             label1.Text = plug.Name; //uzywamy, metod wlasciwosci co tlyko chcemy.
            
        }


0

No jak już wiesz, że coś dziedziczy po interfejsie, którego definicję znasz to rzutujesz i używasz. Dokładnie tak jak napisał to HideYoshi, ehh ;).

0

Dzięki wielkie za pomoc!

0

Witam, przepraszam że odgrzebuję takie stare tematy.
Potrzebuje właśnie takie coś a przykład HideYoshi mi nie działa,

Czy mógłbym prosić o pełny przykład takiej funkcjonalności?

Pozdrawiam

0

Nie dziala, bo? To jest pelny przyklad funkcjonalnosci. Wrzuc swoj kod i opisz jakie bledy leca.

1 użytkowników online, w tym zalogowanych: 0, gości: 1