Avatar billede MikkelNielsen Nybegynder
21. december 2009 - 13:01 Der er 11 kommentarer og
1 løsning

C# loade en dll, instantiere et objekt og kommunikere med det

Hej,

Jeg har et program A, som skal kommunikere med program B (begge skrevet i C#). Kommunikationen skal foregå via et simpelt interface, som jeg definerer. Hvordan gør man det?

Jeg har forsøgt følgende: B er kompileret som en .exe og A starter B sådan her:

System.Diagnostics.Process.Start( "c:\\b.exe" );

Det virker fint i den forstand, at B starter op, men hvordan snakker jeg med den via interfacet?

Jeg har også forsøgt dette: B er kompileret som en .dll (det er en Form, som desuden implementerer MyInterface) og A gør følgende:

Assembly asm = Assembly.LoadFile( "c:\\b.dll" );
Object obj = asm.CreateInstance( "ClassLibrary1.Class1" );

Så langt så godt. Her går det imidlertid galt:

ClassLibrary1.Class1 myClass = (ClassLibrary1.Class1) obj; // Invalid cast exception.

Hvordan gør man EGENTLIG? Jeg vil bare have A og B til at snakke sammen gennem et interface. Det burde være nemt, synes jeg, men kan sgutte lige hitte ud af det.

- Mikkel N.
Avatar billede arne_v Ekspert
21. december 2009 - 13:57 #1
Et normalt C# kald er noget som man bruger ved kald af kode internt i samme process.

Ved kald mellem to processer skal der lidt mere til.

En mulighed i .NET er remoting.

http://www.eksperten.dk/guide/86

Det kan saa ogsaa laves via WCF i nyere .NET versioner.
Avatar billede MikkelNielsen Nybegynder
21. december 2009 - 17:25 #2
Tak Arne_v

Men det må da være muligt at program A loader B.dll og kalder en metode i den? Mit nuværende problem er helt banalt.

I roject B bygger jed nedenstående som en dll:
namespace MyClassLibrary
{
    public class B
    {
        public B()
        {
        }

        public static B Handshake()
        {
            return new B();
        }

        public int AddNumbers( int val1, int val2 )
        {
            return val1 + val2;
        }
    }
}
 
I project A bygger jeg nedenstående som en Windows app. (jeg har added B.dll som en reference til projektet):
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        Assembly asm = Assembly.LoadFile( "B.dll" );
        Object obj = asm.CreateInstance( "MyClassLibrary.B" ); // OK
        MyClassLibrary.B myB = (MyClassLibrary.B)obj; // Invalid cast exception
    }
}


System.InvalidCastException was unhandled
  Message="[A]ClassLibrary.B cannot be cast to [B]ClassLibrary.B. Type A originates from 'ClassLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' at location 'Projects\\ClassLibrary\\ClassLibrary\\bin\\Debug\\B.dll'. Type B originates from 'ClassLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'Projects\\CSharpLoadDll\\CSharpLoadDll\\bin\\Debug\\ClassLibrary.dll'."

Jeg er ikke helt med på, hvad jeg skal stille op med dén fejlmeddelelse.
Avatar billede arne_v Ekspert
21. december 2009 - 17:34 #3
Du kan sagtens kalde kode i en DLL.
Avatar billede MikkelNielsen Nybegynder
21. december 2009 - 17:35 #4
Kan du give mig et 10-liniers fungerende kodeeksempel i stil med det, jeg har præsenteret ovenfor?
Avatar billede arne_v Ekspert
21. december 2009 - 17:36 #5
Du kan enten goere det via reflection eller via at caste til et interface i en anden DLL som baade EXE og den dynamisk DLL refererer til.
Avatar billede arne_v Ekspert
21. december 2009 - 17:37 #6
Reflection:

using System;
using System.Reflection;

class MainClass
{
    public static void test(string dllname, string classname, string methodname)
    {
        object o = Assembly.Load(dllname).CreateInstance(classname);
        o.GetType().InvokeMember(methodname,
                                BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
                                null, o, null);

    }
    public static void Main(string[] args)
    {
        test("A", "A", "Doit");
        test("B", "B", "Doit");
    }
}
Avatar billede arne_v Ekspert
21. december 2009 - 17:38 #7
using System;

public class A
{
    public void Doit()
    {
        Console.WriteLine("I am A");
    }
}
Avatar billede arne_v Ekspert
21. december 2009 - 17:38 #8
Med interface:

using System;
using System.Reflection;

class MainClass
{
    public static void test(string dllname, string classname, string methodname)
    {
        I o = (I)Assembly.Load(dllname).CreateInstance(classname);
        o.Doit();
    }
    public static void Main(string[] args)
    {
        test("A", "A", "Doit");
        test("B", "B", "Doit");
    }
}
Avatar billede arne_v Ekspert
21. december 2009 - 17:38 #9
public interface I
{
    void Doit();
}
Avatar billede arne_v Ekspert
21. december 2009 - 17:39 #10
using System;

public class A : I
{
    public void Doit()
    {
        Console.WriteLine("I am A");
    }
}
Avatar billede MikkelNielsen Nybegynder
22. december 2009 - 11:30 #11
Tak arne_v. Præcist det jeg havde brug for. :)

Hvis du smider et svar, skal jeg nok acceptere det, så du kan få points.
Avatar billede arne_v Ekspert
22. december 2009 - 14:12 #12
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester