26. september 2008 - 14:06Der er
28 kommentarer og 1 løsning
Problem med tilgang til metoder i ClassLibrary (DLL-fil)
Jeg har længe bakset med at få tilgang til nedenstående to metoder. Jeg har brug for et eksempel der viser hvordan jeg i en simpel windows form application får vist teksterne "Hello1" og Hello2" i en Richtextbox, når der trykkes på en knap.
Skal tilgangen til metoderne erklæres i selve dll'en (hvilket er at foretrække)eller i applicationen
Hvis jeg putter NamespaceClassLibrary i using, kan jeg skrive NamespaceClassLibrary.Namespace1.Class1...og så ikke mere!!
Nej, det kan du gøre *uden* using System. Med using System kan du skrive:
Byte.Parse() Byte.TryParse()
etc.
Du kommer under ingen omstændigheder udenom at med mindre du har en instans af din klasse, så kan du kun tilgå statiske (static) metoder. Da du ikke har nogle af dem, er det helt naturligt at du ikke kan komme videre - for du kigger på selve klassen, ikke en instans af den.
Hvad der er bedst i din situation kan der ikke gives et fast svar på, men som tommelfingerregel kan man sige at en metode bør være statisk, hvis den ikke er afhængig af nogen form for interne tilstande. Ellers skal man have fat i en instans først (ved at bruge new).
Når en metode er statisk ligger den på klassen. F.eks. int.Parse(). Når en metode IKKE er statisk, ligger den på objeketet. F.eks. myString.SubString()
OK! Det er rigtigt at det virker med punktumnotationen når metoderne er statiske, men jeg har altså brug for at det er et objekt, som jeg kan oprette flere instanser af.
Men der må da være en måde at få punktumnotationen til at virke selv om det er et object!
Jamen, du har jo fået svaret. Hvis metoden ikke er statisk, så kommer du ikke udenom at oprette en instans, og dermed kan du ikke bare chaine det hele vejen - det er ganske enkelt umuligt, og det giver heller ikke mening - for hvis metoden ikke kan gøres statisk, så må det betyde at du arbejder med nogle instansvariable. Hvis du kunne køre sådan en metode uden en instans, hvor skulle den så lige finde de instansvariable henne? *-)
Husk nu at en metode godt kan være statisk uden at det forhindrer en i at have instanser af klassen. Du kan bare ikke manipulere med ikke-statiske klassevariable fra de statiske metoder.
Der er et designpattern der hedder "Singleton pattern", som går ud på at have en instans a en klasse liggende statisk på klassen. Det kan være det er dette du leder efter? http://en.wikipedia.org/wiki/Singleton_pattern
Noget helt ander er at, du kan godt have en statisk metode på en ikke-statisk klasse. Hvis du f.eks. tager System.String klassen i frameworket. Dette er en ikke-statisk klasse, som du kan oprette instanser af. Men den har alligevel flere statiske metoder, som f.eks. System.String.Format().
Jeg har programmeret Delphi i en del år, men det her C# er lidt nyt for mig, så bær over med mig hvis jeg lyder grøn, for det er jeg ;-)
Denne dll sender blot en kommando... en anden dll sørger for at sende svaret på kommandoen retur til applicationen.
Jeg har nu prøvet at lave det med statiske metoder, men det driller stadig, så nu har jeg lige skåret 5000 linier væk så der kun er 2 kommandoer, måske er det bedre for jer at studerer hvad jeg egentlig sidder og roder med.
Jeg har problemer med at få adgang til HBMux, som er er object... Hvis jeg opretter objektet i selve metoden brokker den sig ikke, men jeg skal kun oprette HBMux én gang
Håber nedenstående kan hjælpe lidt
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MultiplexClassLibrary;
namespace DeviceClassLibrary {
public class HBDataPacket { //Interface selection public bool Enable_COMPortDevice; public bool Enable_CANbusDevice; public bool Enable_ProfibusDevice; public bool Enable_MODBusDevice;
//COMport settings public string COMStartStr; public string COMEndStr; public string COMTxStr; public string COMname; public int COMBaudrate; public bool IncludeStartStr;
//CAN settings public string CANopen;
//Profi settings public string ProfiBus;
//MODbus settings public string Modbus; //Common settings public int Max; public int Min; public string Unit;
public bool Read; public bool Write; public int ReTransmit; public int Timeout; public bool Error; public string ErrorMgs;
public DateTime TxTimeStamp; public int State; public string ReturnAnswer; }
public class HBDevice {
//******MBMultiplex kommer fra DLL'en MultiplexClassLibrary HBMultiplex HBMux = new HBMultiplex(); //******Hvor skal HBMux oprettes***
public static bool _COMPortDevice = false; public static bool _CANbusDevice = false; public static bool _ProfibusDevice = false; public static bool _MODBusDevice = false; public static bool _HBUSBdevice = false; public static string _COMname; public static int _COMBaudrate;
//Constructor for DeviceClassLibrary public HBDevice() { HBMux.NewMultiplexData += new HBMultiplex.MultiplexDataDelegate(DeviceDataRecieved); }
//delegate til event public delegate void DeviceDataDelegate(HBDataPacket datapacket);
// event af typen ComportDataDelegate public event DeviceDataDelegate NewDeviceData;
// Hvis der er abonnenter på eventen, kaldes den. private void OnDeviceData(HBDataPacket datapacket) { if (NewDeviceData != null) NewDeviceData(datapacket); }
public void DeviceDataRecieved(HBDataPacket datapacket) { OnDeviceData(datapacket); }
public static class Commands { public static void _ID_GetDeviceIdentification() { HBDataPacket datapacket = new HBDataPacket();
Du kan oprette en statisk klasse, som indeholder en instans af HPMux klassen. Hvis vi vil have den punktum notation du ønsker, kan vi kalde klassen for MultiplexClassLibrary
public static class MultiplexClassLibrary { private static HBMux _hBMux; public static HBMux HBMux { get { if (_hBMux == null) _hBMux = new HBMux();
return __hBMux; } } }
Nu kan du få fat i koden overalt ved at skrive:
MultiplexClassLibrary.HBMux
For at kalde MultiplexDataSend: MultiplexClassLibrary.HBMux.MultiplexDataSend(datapacket);
Hvis du gør det på denne måde, bliver instansen automatisk oprettet første gang du bruger den. Derfor skal du ikke selv oprette en instans i din kode. Du skal altså fjerne denne linje fra koden du postet: HBMultiplex HBMux = new HBMultiplex();
Du har selvfølgelig helt ret. Jeg mener HBMultiplex!
Og, ja. Ovenstående kode opretter en instans af klassen første gang du bruger den via den statiske property. Altså første gang du skriver:
MultiplexClassLibrary.HBMux.EtEllerAndet().
Alle andre gange du kalder propertien, er det den samme instans der bliver brugt. På denne måde bliver instansen bare oprettet en gang, så længe programmet er åbent.
Men hvordan kan jeg oprette flere instanser af ovenstående "DeviceClassLibrary" fra min application... Før lavede jeg det sådan her:
DeviceClassLibrary.HBDevice.Commands Device2 = new DeviceClassLibrary.HBDevice.Commands();
Men det kan jeg jo ikke nu, så hvordan gør jeg så det?
Her et dump af min test application
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using DeviceClassLibrary;
namespace WindowsFormsApplication1 { public partial class Form1 : Form { DeviceClassLibrary.HBDevice.Commands Device2 = new DeviceClassLibrary.HBDevice.Commands(); *************Tja det har ikke den store virkning nu da metoderne er statiske*******
public Form1() { InitializeComponent(); }
delegate void testdelegate(HBDataPacket datapacket); public void test(HBDataPacket datapacket) { if (this.richTextBox1.InvokeRequired) { testdelegate d = new testdelegate(test); this.Invoke(d, new object[] { datapacket }); } else { this.richTextBox1.AppendText(datapacket.ReturnAnswer); } }
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { //nød til at stoppe invoke eller abonnement på device delegate Device1.NewDeviceData -= new HBDevice.DeviceDataDelegate(test); }
Nu må du altså beslutte dig. Det er dig selv der har sagt at du vil kunne skrive alt hele vejen fra namespace til metodekald (hvorfor du altså ikke har nogen instans at køre på), men samtidigt vil du alligevel oprette instanser. Det giver ikke mening - for enten skal en metode bruge en instans, eller også skal den ikke.
I dit tilfælde skal du vel vide hvilken port der benyttes. Så har du behov for en instans (for du kan jo have gang i flere porte på samme tid), og så duer det ikke at du har metoder der skal kende den oplysning, men samtidigt ikke må få en instans at kigge på - for den oplysning er jo netop instans-afhængig.
"Noget helt ander er at, du kan godt have en statisk metode på en ikke-statisk klasse. Hvis du f.eks. tager System.String klassen i frameworket. Dette er en ikke-statisk klasse, som du kan oprette instanser af. Men den har alligevel flere statiske metoder, som f.eks. System.String.Format()."
Jeg vil gerne kunne benytte min DLL flere gange samtidig i min applikation, så jeg f.eks opretter et object/instans der kommunikerer med COM1 og et andet der komunikerer med COM2... De skal jo bruge den/de samme dll'er... men det er måske ikke muligt?
Jammen! Hvis det er det der skal til, så er jeg måske ved at være ved vejs ende i min problematik.
Hvordan opretter jeg så 2 instanser af min dll: "DeviceClassLibrary.dll"
aaberg'e eksempler har været meget brugbare for mig. Jeg har brug for at få det beskrevet i et kode-eks, for at forstå helt præcis hvad du mener, for jeg er lidt ny i det her.
Så hvis en af jer kan vise hvordan jeg kan oprette 2 instanser af min "DeviceClassLibrary.dll", så vil jeg blive meget meget glad.
Jammen så har jeg da ikke punktum-notationen.... det sidste kode eks. viser hvad jeg har gjort... er det rigtigt... som jeg skrev må du meget gerne give et eks!
Hvis det du har brug for er, at oprette en ny instans af klassen og overskrive den gamle, kan du tilføje en set-metode i den statiske property:
public static class MultiplexClassLibrary { private static HBMultiplex _hBMux; public static HBMultiplex HBMux { get { if (_hBMux == null) _hBMux = new HBMux();
return __hBMux; } set { _hBMux = value; } } }
Så vil du til hver en tid kunne 'resette' din HBMux ved at skrive: HBMultiplexClassLibrary.HBMux = new HBMultiplex();
Dette vil overskrive referencen til objektet, så du mister referencen til det tideligere object. Hvis du har brug for at kunne tilgå flere instanser af HBMultiplex klassen på samme tid, er dette ikke løsningen.
Og en lille tilføjelse: Man kan ikke oprette instanser af en dll. I .NET er en dll et fysisk klassebibliotek. Hvad navnet på dll filen er, skal du bare tænke på imens du browser efter filen i "Add Reference". Når en dll fil er tilføjet et projekt, bliver alle namespaces og klasser i dll filen automatisk en del af det rammeverk du har til rådighed fra din kode. Punktum notationen som man har i .NET har ikke noget med dll'en at gøre, men derimod namespaces. Tager du f.eks. XmlDocument klassen, så ligger den i namespacet System.Xml. At et namespace ofte har samme navn dll filen, er et designspørgsmål. Du kan sagtens have et namespace som hedder MyCompany.Classes i en dll som hedder ClassLib.dll
Tak for det fine eks… det får jeg faktisk brug for i en anden sammenhæng, men lad mig lige forklare det lidt mere detaljeret.
Jeg har 3 dll’er
<DeviceClassLibrary.dll>: Indeholder alle kommandoer. Metoderne sender blot en pakke af sted. En delegate sørger for at returnere resultaterne til selve applicationen.
<MultiplexClassLibrary.dll> Vælger Interface eks: COM, LAN, CAN, ProfiBus…osv og sender pakkerne frem og tilbage. Dvs alle pakker går via denne DLL.
<ComportClassLibrary.dll> Komunikerer med COM porten… en delegate returnerer resultat til Multiplex dll’en og videre tilbage til DeviceClassLibrary.
Senere kommer der så også en LANClassLibrary.dll, en CANClassLibrary.dll... osv
Jeg ville gerne have at programøren blot kunnen tilføje <DeviceClassLibrary> og så blive præsenteret for alle metoderne. Men jeg har også brug for at kunne oprette flere instanser af Komando-klassen, så jeg kan have en device der kommunikerer med LAN Samtidig med en anden på COM... MEN jeg vil også meget gerne have punktumnotationen eks:
New Device1 (kommunikerer eks via COM) New Device2 (kommunikerer eks via LAN)
Så vidt jeg forstår dig nu, så vil du på en måde inddele metoder og properties i en klasse i kategorier, og få brugeren til at bruge punktumnotationen til at navigere disse kategorier. Dette kan ikke lade sig gøre.
Hvis du vil have punktumnotationen:
Device1.Commands.Get.Identification
Så skal du have en property i Device klassen som hedder Commands. Denne property skal indeholde en instans af en klasse som har en Property der hedder Get, som indeholder en instans af en klasse med som har en property der hedder Identifikation.. osv.
Men det du egentlig prøver på, er at lave om på designet af programmeringssproget. Hvorfor ikke bare have en GetIdentification() metode på Device klassen? Tror du ikke at brugeren forstår at GetIdentification er en kommando? Hvis Ikke, så kald metoden Device1.CommandGetIdentification(). Punktumnotationen er i C# til at navigere i namespaces og klasser/properties/metoder, hvis du laver om på dette, bliver brugerne af klasserne totalt forvirret. Det vil i hvert fald ikke gøre det mere overskueligt.
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.