Avatar billede nemezis_aalborg Nybegynder
27. oktober 2004 - 20:04 Der er 17 kommentarer og
1 løsning

Bruge class i assembly

Hejsa,
er løbet ind i et lille problem med hensyn til at loade assemblies i C#

Jeg har en række klasser, der nedarver fra følgende interface:

Interface.dll
--------------------------------------
namespace DriverInterface
{
    public abstract class StreamInterface : System.IO.Stream
    {
        #region constructor
        public StreamInterface(string connection)
        {
        }
        #endregion
    }
}
--------------------------------------

Når jeg vil loade en instans af en dll, der nedarver fra interfacet gør jeg sådan her:

Client.exe
--------------------------------------
public sealed class Driver
{
    public DriverInterface.StreamInterface RequestStream(string assemblyName, string connection)
    {
        System.Reflection.Assembly DataProvider;

        DataProvider = System.Reflection.Assembly.LoadFrom(assemblyName);

        DriverInterface.StreamInterface instance =
                (DriverInterface.StreamInterface)
                    DataProvider.CreateInstance(
                        "DriverInterface.StreamInterface");

        return instance;
    }
}
--------------------------------------

Er dette den rigtige måde at gøre det på? og hvordan får jeg overført variablen connection til constructoren?

På forhånd tak!
Avatar billede arne_v Ekspert
27. oktober 2004 - 20:13 #1
Den nemmeste løsning er at lave en constructor uden argumenter og enten
en Property eller en Set metode til at sætte connection med.
Avatar billede arne_v Ekspert
27. oktober 2004 - 20:16 #2
Ellers tror jeg at du skal igang med GetType() og GetConstructors() og Invoke()
Avatar billede arne_v Ekspert
27. oktober 2004 - 20:16 #3
Hvis du vil den sidste vej kan jeg godt forsøge at bixe et eksempel.
Avatar billede nemezis_aalborg Nybegynder
27. oktober 2004 - 20:19 #4
Vil super gerne se et eksempel på det sidste.
Avatar billede arne_v Ekspert
27. oktober 2004 - 20:23 #5
Jeg går igang
Avatar billede nemezis_aalborg Nybegynder
27. oktober 2004 - 20:34 #6
Har fundet ud af at CreateInstance tager "object[] args", men ved ikke rigtigt hvad de andre argumenter betyder...

[C#]
public object CreateInstance(
  string typeName,
  bool ignoreCase,
  BindingFlags bindingAttr,
  Binder binder,
  object[] args,
  CultureInfo culture,
  object[] activationAttributes
);
Avatar billede arne_v Ekspert
27. oktober 2004 - 20:38 #7
A.cs
====

using System;

public abstract class A
{
    private int v;
    public A(int v)
    {
        this.v = v;
    }
    public abstract int GetOffset();
    public void Show()
    {
        Console.WriteLine(v + GetOffset());
    }
}

C.cs
====

public class C : A
{
    private int offset;
    public C(int v, int offset) : base(v)
    {
        this.offset = offset;
    }
    public override int GetOffset()
    {
        return offset;
    }
}

Test.cs
=======

using System;
using System.Reflection;

class TestClass
{
    public static void Test(string dllname, string classname, int v, int offset)
    {
        Assembly asm = Assembly.Load(dllname);
        Type typ = asm.GetType(classname);
        Type[] ctordeclargs = { typeof(int), typeof(int) };
        ConstructorInfo ctor = typ.GetConstructor(ctordeclargs);
        object[] ctorcallargs = { v, offset };
        A o = (A)ctor.Invoke(ctorcallargs);
        o.Show();
    }
    public static void Main(string[] args)
    {
        Test("C", "C", 1, 2);
    }
}

build
=====

csc /t:library A.cs
csc /r:A.dll /t:library C.cs
csc /r:A.dll /t:exe Test.cs
Avatar billede wisen Nybegynder
27. oktober 2004 - 20:42 #8
Grundlæggende ser det jo fint ud... jeg ville måske vælge at lave en FactoryMethod i din .dll - istedet for at instantiere objekterne direkte fra Client.exe
Avatar billede arne_v Ekspert
27. oktober 2004 - 20:44 #9
Test.cs kan faktisk laves simplere med den CreateInstance du har fundet:

using System;
using System.Reflection;

class TestClass
{
    public static void Test(string dllname, string classname, int v, int offset)
    {
        Assembly asm = Assembly.Load(dllname);
        object[] ctorcallargs = { v, offset };
        A o = (A)asm.CreateInstance(classname, false, BindingFlags.Public | BindingFlags.Instance, null, ctorcallargs, null, null);
        o.Show();
    }
    public static void Main(string[] args)
    {
        Test("C", "C", 1, 2);
    }
}
Avatar billede nemezis_aalborg Nybegynder
27. oktober 2004 - 20:44 #10
Tester lige ;)
Avatar billede arne_v Ekspert
27. oktober 2004 - 20:45 #11
wisen>

Der er sikkert en del der kan smukkeseres.

Koden skal bare vise hvordan reflection kaldene kan laves.

Indpakningen regner jeg med at nemezis selv sørger for.
Avatar billede arne_v Ekspert
27. oktober 2004 - 22:12 #12
og et svar såfremt du får det til at virke
Avatar billede nemezis_aalborg Nybegynder
02. november 2004 - 09:33 #13
Dit eksempel virker fint, men jeg kender kun stien til dll'en så jeg er nødt til at bruge LoadFrom, men så virker det af en eller anden grund ikke :/
Avatar billede nemezis_aalborg Nybegynder
02. november 2004 - 09:39 #14
Og lige lidt mere info for resten. Har prøvet en del på at få det til at virke, men den smider en FileNotFoundException. Virkelig underligt, for når jeg udskriver stien, og checker den i Explorer/Dos-prompt, så er den der????
Avatar billede nemezis_aalborg Nybegynder
02. november 2004 - 09:45 #15
Ups.. skrev vist noget forkert. Det er hvis jeg bruger Load, den failer; naturligvis, da jeg bruger stien og ikke assembly navnet.

Men hvis jeg bruger LoadFrom failer den når jeg bruger CreateInstance med følgende

exceptUnhandled Exception: System.Reflection.TargetInvocationException: Exception has
been thrown by the target of an invocation. ---> Driver.DriverConnectionFormatEx
ception: Invalid file access type.
  at Driver.File.Setup(String argument)
  at Driver.Stream..ctor(String argument)
  at Driver.File..ctor(String argument)
  --- End of inner exception stack trace ---
  at System.Reflection.RuntimeConstructorInfo.InternalInvoke(BindingFlags invok
eAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean isBinder
Default)
  at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, B
inder binder, Object[] parameters, CultureInfo culture)
  at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder bin
der, Object[] args, CultureInfo culture, Object[] activationAttributes)
  at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binde
r binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
  at System.Reflection.Assembly.CreateInstance(String typeName, Boolean ignoreC
ase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture
, Object[] activationAttributes)
  at Driver.Loader.createInstance(Assembly assembly, String name, Object[] ctor
callargs)
  at Driver.Loader.RequestStream(String connection)
  at Driver.Implementaion.Main(String[] args)ion:
Avatar billede arne_v Ekspert
02. november 2004 - 23:16 #16
Mystisk. Den her virker hos mig:

using System;
using System.Reflection;

class TestClass
{
    public static void Test(string filename, string classname, int v, int offset)
    {
        Assembly asm = Assembly.LoadFrom(filename);
        object[] ctorcallargs = { v, offset };
        A o = (A)asm.CreateInstance(classname, false, BindingFlags.Public | BindingFlags.Instance, null, ctorcallargs, null, null);
        o.Show();
    }
    public static void Main(string[] args)
    {
        Test(@"C:\E\C.dll", "C", 1, 2);
    }
}
Avatar billede nemezis_aalborg Nybegynder
02. november 2004 - 23:29 #17
Har fundet ud af det :)

Det er for createInstance åbenbart pakker exceptions smidt i constructoren i en System.Reflection.TargetInvocationException så den ikke blev fanget af mine catch blokke... Meget underligt men jo egenlig fint nok.. hvis man altså lige ved det :)

Point til dig arne_v
Avatar billede nemezis_aalborg Nybegynder
02. november 2004 - 23:29 #18
for = fordi ..?
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