Laden...
Avatar #avatar-3152.png
TheBrainiac myCSharp.de - Member
Lehramt Informatik & Mathe - Student /dev/null Dabei seit 17.12.2006 795 Beiträge
Benutzerbeschreibung

Forenbeiträge von TheBrainiac Ingesamt 795 Beiträge

05.08.2010 - 12:30 Uhr

Aber er ist immernoch gezwungen, alles neu zu konfigurieren.

Naja, ist eh egal. Ich hab es inzwischen so wie oben beschrieben gelöst (mit Server).

Gruß, Christian.

05.08.2010 - 11:25 Uhr

Auch das hatte ich mir schon überlegt. Nur muss so der Benutzer trotzdem die Default-Werte der Konfiguration überschreiben.

Gruß, Christian.

05.08.2010 - 11:24 Uhr

Habe das oben genannte schon implementiert (Reversible Ticket mit Encoder / Decoder), bin aber gerade nicht am richtigen PC.

Außerdem habe eine Option für Base36-Encoding hinzugefügt.

Werde es heute abend hochladen.

Gruß, TheBrainiac.

04.08.2010 - 18:30 Uhr

Habe gerade einen Ticket-Generator geschrieben.

04.08.2010 - 18:29 Uhr

Beschreibung:

Da ich gerade an einem Account-Aktivierungs-System arbeite, brauche ich sichere und eindeutige Links, die ich per Mail senden kann.

Bisher habe ich immer Guid verwendet, aber angeregt durch diesen Thread generiere ich meine Tickets jetzt selbst.

Hier die Methode samt kleiner Test-Anwendung

using System;
using System.Text;
using System.Security.Cryptography;

public class MyClass
{
	public static void Main()
	{
		Console.WriteLine("Ticket (strong, base64):");
		Console.WriteLine(CreateTicket("TheBrainiac", true, true));
		Console.WriteLine("Ticket (strong, hex):");
		Console.WriteLine(CreateTicket("TheBrainiac", true, false));
		Console.WriteLine("Ticket (weak, base64):");
		Console.WriteLine(CreateTicket("TheBrainiac", false, true));
		Console.WriteLine("Ticket (weak, hex):");
		Console.WriteLine(CreateTicket("TheBrainiac", false, false));
	}
	
	public static string CreateTicket(string customData, bool strong, bool base64) {
		RandomNumberGenerator provider = RNGCryptoServiceProvider.Create();
		
		byte[] randomData = new byte[64];
		provider.GetNonZeroBytes(randomData);
		
		byte[] stringData = Encoding.Default.GetBytes(customData);
		byte[] timeData = BitConverter.GetBytes(DateTime.Now.Ticks);
		
		byte[] allData = new byte[randomData.Length + stringData.Length + timeData.Length];
		Array.Copy(randomData, 0, allData, 0, randomData.Length);
		Array.Copy(stringData, 0, allData, randomData.Length, stringData.Length);
		Array.Copy(timeData, 0, allData, randomData.Length + stringData.Length, timeData.Length);
		
		HashAlgorithm hash = strong ? (HashAlgorithm) SHA512Managed.Create() : (HashAlgorithm) MD5.Create();
		
		byte[] hashData = hash.ComputeHash(allData);
		
		if (base64) {
			return Convert.ToBase64String(hashData).ToUpper();
		} else {
			StringBuilder sb = new StringBuilder();
			
			for (int i = 0; i < hashData.Length; i++) {
				sb.Append(Convert.ToString(hashData[i], 16));
			}
			
			return sb.ToString().ToUpper();
		}
	}
}

Die Ausgabe ist in diesem Fall:

Ticket (strong, base64):
PL1FEQVVI/IRBFUFUQVMHSNQQG+OOJFCSF7IYEV9GHGWC8Y+BXXHIKVEVSHGHHIQHCU/HMI72MXP69OZKMHC+G==
Ticket (strong, hex):
906DCF4321B9F98D2AF6FCF46B3C759DC966FEFFFC6E64B7F42726EC7F9B6AE3551FCF6B25ED2CD4FAE1A6A4FA6CAE1CE26B6B8C3620A053F8C1DEFEA88A
Ticket (weak, base64):
UHBFASXCG2OQ9NZA32+9CG==
Ticket (weak, hex):
4DBB374EBC3BC195CC93AD97A8816D

Gruß, Christian.

Schlagwörter: <Bitte Schlagwörter, unter denen das Snippet über die Suche gefunden werden soll, hier eintragen>

04.08.2010 - 17:19 Uhr

Das ist mir bekannt.

Ich wollte halt eigentlich, dass die .exe einfach per Copy&Paste verteilbar ist und ihre Einstellungen in sich selbst speichert, damit man nicht durch versehentliches "nicht-mit-kopieren" der Konfigurationsdateien alles neu eingeben muss. Ist also praktisch sowas wie PortableApps, nur Firmenintern.

Ich werde die Einstellungen wahrscheinlich zentral auf unserem Server speichern. Scheint mir bis jetzt die einfachste Lösung. Und da auf unseren Laptops jeder einen VPN-Zugang hat, bietet sich das an.

Gruß, Christian.

03.08.2010 - 19:01 Uhr

Hi @ All.

Gibt es eine Möglichkeit, die in einer .exe eingebetteten Resourcen zur Laufzeit per Code zu ändern? Also so etwas wie myResourceManager.++S++etObject anstatt myResourceManager.GetObject?

Oder gibt es eine andere Möglichkeit, bestimmte Daten änderbar in der .exe zu Speichern?

Gruß, Christian.

03.08.2010 - 17:20 Uhr

Ich vermute, du meinst RegexOptions.IgnoreCase. Zumindest bezog sich CSL Einwand auf die Groß-/Kleinschreibung und nicht auf Zeilenumbrüche.

Stimmt. Das meinte ich.

02.08.2010 - 22:41 Uhr

@herbivore:
In meiner Lösung hatte ich es ja mit \((?<parameters>.*?)\), was es auch tun sollte, da das .*? ja nicht gierig ist, oder?

Gruß, Christian.

01.08.2010 - 12:11 Uhr

Das sollte helfen:

((?<dll>_dll)\s+)?func(tion)?\s+(?<name>\w+)(\s+)?(\((?<parameters>.*?)\))

Gruß, Christian.

26.07.2010 - 16:35 Uhr

Angenommen, ctrl sei dein SplitContainer:

using (var bmp = new Bitmap(ctrl.Width, ctrl.Height)) {
    ctrl.DrawToBitmap(bmp, new Rectangle(0, 0, ctrl.Width, ctrl.Height));

    bmp.Save(/*SoWieSo*/);
}

Gruß, Christian.

26.07.2010 - 10:32 Uhr

Hi, chip777!

Sieh dir mal Control.DrawToBitmap(...) an!

Gruß, Christian.

19.07.2010 - 23:25 Uhr

Schön sauber und übersichtlich 🙂

Aber mein Temp-Ordner ist immer noch an die 12 GB groß...

Gruß, Christian.

18.07.2010 - 12:44 Uhr

User: By the way, are you male or female?

Cleverbot: Male.

User: But your picture shows a female!

Cleverbot: That's someone else's picture.

User: Or you are a gender-changer...

Cleverbot: You got me again 😃.

16.07.2010 - 19:44 Uhr

Ich hab sowas schon ein paar mal umgesetzt und Guid hat immer gelangt 😭

Gruß, Christian.

16.07.2010 - 19:41 Uhr

Mh. Dachte ich mir.

Habs jetzt so gelöst (Rück- / Aufwärts). Wollte es zwar ohne Eltern-Property hinkriegen, also (Vor- / Abwärts), aber so ist wahrscheinlich performanter.

Danke & Gruß, Christian.

16.07.2010 - 18:21 Uhr

wenn es nicht gerade um winzige oder ganz spezielle Graphen geht...

Der Graph hat eine maximale Tiefe von 25 und ist ähnlich wie ein TreeNode.

Ist das winzig oder speziell? 🤔

Bzw. was wäre denn dann angebracht?

Gruß, Christian.

16.07.2010 - 18:01 Uhr

Hi @ All.

Ich habe folgende Klasse (vereinfacht)

class Node {
    string Name;
    Node[] Nodes;
}

Nun muss ich eine Methode implementieren, die mir den Pfad zwischen zwei Nodes berechnet:

Node[] FindPath(Node start, Node end) {
    
}

Wie kann ich das bewerkstelligen? Ist da ein Pfadfinder-Algorithmus (A*) angebracht? Oder geht es einfacher?

Gruß, Christian.

14.07.2010 - 12:46 Uhr

Danke für den Tipp, aber hat leider nichts gebracht.

13.07.2010 - 11:52 Uhr

Hi @ All!

Nutzt von euch jemand Last.fm?
Ich habe es im Mai entdeckt und nutze es seitdem regelmäßig (Link).

Gruß, Christian.

12.07.2010 - 20:02 Uhr

Ich verwende das auch so wie du, nur hab ich den Singleton anders implementiert:

public class Factory
{
	private static readonly Factory m_Instance = new Factory();
	
	static Factory() { }
	
	private Factory() { }
	
	public static Factory Instance {
		get { return m_Instance; }
	}
}

Gruß, Christian.

12.07.2010 - 18:19 Uhr

Also. 1und1 konnte (wollte?) mir nicht helfen. X(

Nach 10 Minuten Fragen beantworten und Zahlen ins Telefon eintippen werde ich endlich zu einem "fähigen" Techniker durch gestellt. Ich hab ihm dann das Problem erklärt. Dann:

1und1: "Wir haben keine interne Weiterleitung."
Ich: "Doch. Ich bekomme einen 301 'Moved Permanently'".
1und1: "Was ist das?"
Ich: "Das ist die Weiterleitung. Ich vermute, es liegt an eurer Konfiguration vom Apache."
1und1: "Moment, ich frage mal einen Kollegen."

Gefühlte 10 Minuten Warteschleife später:

1und1: "Mein Kollege konnte auch keine Erklärung für das Verhalten finden. Tut mir leid."

Dann wollte er mir noch weis machen, dass das von einer TYPOlight-Installation in einem ganz anderen Verzeichnis kommen soll. (Kann nicht sein, macht erstens keine 301-Weiterleitungen und zweitens ist es in einem ganz anderen Verzeichnis. Wie sollte dann Apache dessen .htaccess-Dateien auf mein Problem-Verzeichnis anwenden?!

1und1: "Tut mir Leid, ich kann ihnen leider nicht weiter helfen."

Da hab ich aufgelegt. Wenigstens war der Techniker freundlich...

Hat jemand von euch eine Idee, wie ich das abgestellt kriege (mittels .htaccess)? Oder wenigstens, nach was ich googlen kann (googlen nach "apache 301 sowieso" bringt mich nur auf Seiten, die zeigen, wie ich eine Weiterleitung zustande kriege, nicht, wie ich diese abstelle...)?

Gruß, Christian.

11.07.2010 - 22:55 Uhr

So. Hab jetzt dank WireShark rausgefunden, dass mir der Apache HTTP 301 "Moved Permanently" sendet. Kann ich das irgendwie abstellen?

Gruß, Christian.

11.07.2010 - 20:56 Uhr

Also:

Ich hab deinen Rat befolgt, und der Server scheint die Anfrage automatisch umzuleiten. D.h., dass, wenn ich xxx-47 in die Adresszeile eingebe, der Server das automatisch umleitet. Danach steht xxx-46 in der Adresszeile. Wie kann ich das abstellen?

Server ist ein Apache (1und1), genaueres weis ich nicht.

Gruß, Christian.

11.07.2010 - 13:18 Uhr

Hi @ All.

Ich benutze einen WebClient, um bestimmte Informationen von meinem WebSpace herunterzuladen.

Angenommen ich habe nur eine Datei 2010-07-11-11-46 (TimeStamp als Dateiname) auf dem WebSpace.

Wenn ich jetzt aber eine Datei 2010-07-11-11-4**++7++** anfordere, lädt er mir die oben genannte Datei runter?!

Liegt das am Server (Apache), dass dieser das irgendwie umleitet, oder am WebClient?

Wie kann ich das ab-/feststellen?

Gruß, Christian

06.07.2010 - 22:15 Uhr

Du hast anfänglich ein Kontingent (Quota) von 1.000.000 Bits. Jede(r) zufallsgenerierte Zahl / String konsumiert einige davon. Jede Nacht um 0:00 CEST bekommst du 200.000 freie Bits. Wenn du an einem Tag alle deine Bits verbraucht hast, bekommst du einen Fehler (503) und kannst keine weiteren Zufallszahlen erzeugen.

Zur Verfügbarkeit kann ich nicht viel sagen, bin auch heute erst drüber gestoßen und hab mir den Wrapper gebastelt.

Gruß, Christian.

06.07.2010 - 18:52 Uhr

Beschreibung:

Der RandomDotOrgClient ist ein einfacher Client, um die Dienste von random.org in .Net nutzen zu können.

Verwendung:

Console.WriteLine("10 Integers [-50;50]:");
var client = new RandomDotOrgClient();
var ints = client.GetIntegers(10, -50, 50);
            
foreach (var i in ints) {
    Console.Write("{0} ", i);
}
Console.WriteLine();

Download & Dokumontation:
Den Download und die Dokumentation findet ihr hier!

Gruß, Christian.

Schlagwörter: random org client zufall zahl

04.07.2010 - 23:50 Uhr

Was du aber machen kannst ist Folgendes:

public static T Method<T>() where T : ITest, new() {
    T t = new T();
    return t;
}

Gruß, Christian.

03.07.2010 - 10:11 Uhr

Hi, MarsStein.

Du bist dran!

Gruß, Christian.

29.06.2010 - 18:04 Uhr

Ich habe das Projekt wieder etwas erweitert. Man kann nun auch serialisierbare Objekte speichern, die nicht von EntityBase ableiten.

Änderungen siehe in den vorherigen Posts.

28.06.2010 - 22:20 Uhr

Die Mods/Admins werden berechtigterweise sagen, dass das Grundlagen sind und den Thread schließen.

Aber ich will mal nicht so sein:

Abboniere eine Funktion void MyLabel_Click(object sender, EventArgs e); für jedes einzelne Label.

Da schreibst du dann deinen Code rein.

Das angeklickte Label bekommst du, indem du sender auf Label castest.

Gruß, Christian.

// Edit: Gnahhh, zu langsam 😛

27.06.2010 - 18:38 Uhr

Hast du den FlashPlayer installiert?

27.06.2010 - 16:50 Uhr

Hi.

Du must ein COM-Objekt einbinden: AxShockwaveFlash

Gruß, Christian.

25.06.2010 - 17:35 Uhr

So.

Ich habe die aktuelle Version im ersten Post hochgeladen.

Das De-/Serialisieren läuft jetzt so ab:

public class Person : EntityBase
{
    protected override void Deserialize(EntityReader reader) {
        m_FirstName = reader.GetString("FirstName");
        m_LastName = reader.GetString("LastName");
        m_Salutation = reader.GetString("Salutation");
        m_Gender = (Gender) reader.GetInt32("Gender");
        m_DateOfBirth = new DateTime(reader.GetInt64("DateOfBirth"));
        
        foreach (var entity in reader.GetReferencedEntities("Addresses")) {
            m_Addresses.Add((AddressBase)entity);
        }
        
        m_Tag = reader.GetObject("Tag");
    }

    protected override void Serialize(EntityWriter writer) {
        writer.Set("FirstName", m_FirstName);
        writer.Set("LastName", m_LastName);
        writer.Set("Salutation", m_Salutation);
        writer.Set("Gender", (int)m_Gender);
        writer.Set("DateOfBirth", m_DateOfBirth.Ticks);
        writer.SetReferencedEntities("Addresses", m_Addresses);
        writer.Set("Tag", m_Tag);
    }
}

Gruß, Christian.

// Edit: An aktuelle Version angepasst. (Eigenschaft Tag hinzugefügt...)

25.06.2010 - 10:46 Uhr

Hi, Blacal.

Ich habe die Klasse schon erweitert, sodass man um das eigentliche XML herumkommt. Bin aber gerade auf Arbeit. Werde den neuen Stand heute Abend hochladen.

Gruß, Christian.

24.06.2010 - 23:20 Uhr
[Designer("System.Windows.Forms.Design.ButtonBaseDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public class Button : ButtonBase, IButtonControl
{
    // Snip
}

Der ButtonDesigner handlet das ganze hier. Du musst dir deinen eigenen Designer schreiben.

Gruß, Christian.

19.06.2010 - 21:32 Uhr

Beschreibung:

EntityDocument ist eine einfache Klasse zur Erstellung von Xml-Dokumenten mit Entitäts-Klassen als Inhalt.

Da Code mehr als 1.000 Worte sagt:

Folgende Daten werden im Beispiel benutzt

Herr Wurst, Hans [19.06.1987; Male]
  PostalAddress (privat) Baumallee 1, 12345 Baumhausen, Deutschland
  PostalAddress (geschäftlich) Stahlstraße 1, 12345 Eisenhausen, Deutschland
  EMailAddress (privat) hans@wurst.de
  EMailAddress (geschäftlich) h.wurst@stahlfirma.de

Zum Speichern:

var hansWurst = new Person() {
    FirstName = "Hans",
    LastName = "Wurst",
    Salutation = "Herr",
    Gender = Gender.Male,
    DateOfBirth = new DateTime(1987, 6, 19),
    Tag = Image.FromFile(@"C:\myImages\test.png")
};

hansWurst.Addresses.Add(new PostalAddress() {
                            Name = "privat",
                            Locality = "Baumallee 1",
                            ZipCode = "12345",
                            City = "Baumhausen",
                            Country = "Deutschland"
                        });

hansWurst.Addresses.Add(new PostalAddress() {
                            Name = "geschäftlich",
                            Locality = "Stahlstraße 1",
                            ZipCode = "12345",
                            City = "Eisenhausen",
                            Country = "Deutschland"
                        });

hansWurst.Addresses.Add(new EMailAddress() {
                            Name = "privat",
                            EMail = "hans@wurst.de"
                        });

hansWurst.Addresses.Add(new EMailAddress() {
                            Name = "geschäftlich",
                            EMail = "h.wurst@stahlfirma.de"
                        });

EntityDocument.Save("hans-wurst.xml", hansWurst);

Zum Laden:

var entities = EntityDocument.Load("hans-wurst.xml");

var person = (Person) entities[0];

var image = person.Tag as Image;

if (image != null) {
    myControl.BackgroundImage = image;
}

Dieses Snippet erzeugt folgendes XML-Markup:

<?xml version="1.0" encoding="utf-8"?>
<EntityDocument>
  <Types>
    <Type name="PostalAddress" type="StudyManager.Data.Entities.PostalAddress, StudyManager, Version=1.0.3832.30437, Culture=neutral, PublicKeyToken=null" />
    <Type name="EMailAddress" type="StudyManager.Data.Entities.EMailAddress, StudyManager, Version=1.0.3832.30437, Culture=neutral, PublicKeyToken=null" />
    <Type name="Person" type="StudyManager.Data.Entities.Person, StudyManager, Version=1.0.3832.30437, Culture=neutral, PublicKeyToken=null" />
  </Types>
  <TopLevel>
    <Entity id="{6df21ebd-420e-4184-b850-e7c5077264ab}" />
  </TopLevel>
  <Entities>
    <Entity type="PostalAddress" id="{b4d64d17-f75d-4153-81fb-6880a595bda7}">
      <Name><![CDATA[privat]]></Name>
      <Locality><![CDATA[Baumallee 1]]></Locality>
      <ZipCode><![CDATA[12345]]></ZipCode>
      <City><![CDATA[Baumhausen]]></City>
      <Country><![CDATA[Deutschland]]></Country>
    </Entity>
    <Entity type="PostalAddress" id="{c1680124-e168-485f-b9cf-e46beeefa4e6}">
      <Name><![CDATA[geschäftlich]]></Name>
      <Locality><![CDATA[Stahlstraße 1]]></Locality>
      <ZipCode><![CDATA[12345]]></ZipCode>
      <City><![CDATA[Eisenhausen]]></City>
      <Country><![CDATA[Deutschland]]></Country>
    </Entity>
    <Entity type="EMailAddress" id="{9e8a808a-f08c-43d4-bcf1-cc449c617403}">
      <Name><![CDATA[privat]]></Name>
      <EMail><![CDATA[hans@wurst.de]]></EMail>
    </Entity>
    <Entity type="EMailAddress" id="{eaa32faf-c3c6-4ff6-8ca7-1db606023be8}">
      <Name><![CDATA[geschäftlich]]></Name>
      <EMail><![CDATA[h.wurst@stahlfirma.de]]></EMail>
    </Entity>
    <Entity type="Person" id="{6df21ebd-420e-4184-b850-e7c5077264ab}">
      <FirstName><![CDATA[Hans]]></FirstName>
      <LastName><![CDATA[Wurst]]></LastName>
      <Salutation><![CDATA[Herr]]></Salutation>
      <Gender value="1" />
      <DateOfBirth value="626866560000000000" />
      <Addresses>
        <Entity id="{b4d64d17-f75d-4153-81fb-6880a595bda7}" />
        <Entity id="{c1680124-e168-485f-b9cf-e46beeefa4e6}" />
        <Entity id="{9e8a808a-f08c-43d4-bcf1-cc449c617403}" />
        <Entity id="{eaa32faf-c3c6-4ff6-8ca7-1db606023be8}" />
      </Addresses>
      <Tag isSerializable="true"><!-- Hier steht normalerweise ein CDATA-Block mit Base64-encodierten Daten. Den habe ich hier weg gelassen. Wäre zu lange :-P --></Tag>
    </Entity>
  </Entities>
</EntityDocument>

Download & Dokumontation:
Den Download und die Dokumentation findet ihr ab sofort hier!

**ChangeLog:***25.06.10: Serialisierung und Deserialisierung von XML unabhänig gemacht: *25.06.10: Klasse EntityReader hinzugefügt *25.06.10: Klasse EntityWriter hinzugefügt *25.06.10: Methode LoadPropertiesFromDocument in Deserialize *25.06.10: Methode SavePropertiesToDocument in Serialize umbenannt. *29.06.10: Der Klasse Person die Eigenschaft Tag hinzugefügt. *29.06.10: Den Klassen EntityReader und EntityWriter jeweils Methoden zum Speichern / Laden von Objekten hinzugefügt

Schlagwörter: entity document xml serialization serialisierung entität dokument

16.06.2010 - 20:27 Uhr

Angenommen ein SpecialChip ist ein Chip mit Display und es sind zwei davon angeschlossen.

Dann willst du vielleicht auf Display1 Die CPU-Auslastung anzeigen und auf Display2 die RAM-Auslastung.

So hatte ich das mit den Chips verstanden.

Gruß, Christian.

16.06.2010 - 17:15 Uhr

Also so wie ich das verstande habe schon.

Ich hatte das so ähnlich gedacht wie mit den COM-Ports. Du hast da auch deine Identifier (COM1, COM2, etc), die du dann CreateFile(NameDesComPorts, ...) öffnest. Das CreateFile ist dann in etwa sowas wie meine ChipFactory. Und auch das Disposen ist imho unnötig, da die Hardware ja vermutlich solange das Programm läuft nicht geändert wird --> Also braucht man pro angeschlossenem Chip immer nur eine Instanz der Chip-Klasse. Und das handlet halt meine ChipFactory. Der Nachteil bei deiner Idee mit TryGet ist halt, dass man dann nicht explizit COM5 öffnen kann, sondern dafür zuerst COM1-4 öffnen muss um überhaupt an COM5 dranzukommen...

Gruß, Christian.

16.06.2010 - 00:07 Uhr

Hi.

Sagen wir mal, du hast ein System mit einzig und alleine vier SpecialChips.

Wie handlest du das?

Meins handelt das so:

Die ChipFactory liest die Daten aus. Sie erzeugt 4 ChipInfo's (für jeden Chip einen) und gibt ihnen die Namen Special1, Special2, Special3 und Special4.

Mittels ChipFactory.GetChip("++Special2++&quot;) kann ich mir dann den zweiten direkt holen. Ich muss dann zwar casten, aber das kann man doch in Kauf nehmen, oder?

15.06.2010 - 23:08 Uhr

@ErfinderDesRades:

Deine Beispiele setzen dann aber voraus, dass es von jeder Klasse nur einen Hardware-Chip gibt. Meine Factory liest alle Chips aus und gibt auf Anfrage die Namen zurück. Aber im Großen und Ganzen hast du Recht: Es ist Geschmackssache. Wenn es aber wie Locutus sagt zu Übungszwecken ist, dann sollte man bewusst schon mal ein bisschen auf die Architektur achten.

Gruß, Christian.

15.06.2010 - 17:06 Uhr

Soweit ich sehe, verhindert eine public static Factory-Klasse durchaus nicht, dass innerhalb eines Chips SystemInformationen zugreifbar sind, denn die factory ist ja public, hier [...] scheint sich schamese zu irren.

Stimmt so nicht. Die SystemInformationen sind innerhalb der Chip-Klasse durchaus abrufbar, aber eben nur diejenigen Informationen, die den Chip selbst repräsentieren. Die Informationen anderer Chips sind nicht abrufbar.

Ich fände es halt "aufgeräumter", wenn ich alles aus einer Datei beziehen kann, als dass ich drauf achten muss, was wo in welchem Verzeichnis liegt. [...] Da hilft eigentlich nur, eine Assembly global in den GAC zu packen, um dem Chaos zu entgehen... [...]

Ich drehe die Frage mal rum: Was spricht gegen eine Einzeldateilösung?

Grundsätzlich spricht nichts dagegen. Aber: Ich persönlich finde es gar nicht schlimm, wenn eine Anwendung mit vielen DLL's im Anwendungsverzeichnis ausgeliefert wir. Das zeugt von Modularität / Austauschbarkeit (gute Möglichkeit, Updates einzuspielen) und Professionalität. Wenn man andererseits eine Anwendung hat, die keine anderen Dateien braucht, fördert das die "Mobilität" der Anwendung. Aber da du sowieso von der Hardware abhängig bist, sollte das imho keine Rolle spielen. Weiterhin ist es gar nicht so einfach, das ganze dann zur Runtime zu entpacken, richtig zu platzieren und dann zu laden. (Gerade mit DllImport).

Gruß, Christian.

14.06.2010 - 23:38 Uhr

da bin ich mit meinem Verständnis einer Assembly grad etwas daneben gelegen.

Naja, ein bisschen 🤔 Siehe Hier

Nach allem was ich bis jetzt rausgefunden habe, wäre die einzige Möglichkeit, eine DLL (= Assembly) zu erzeugen, richtig? Und diese DLL kann ich dann direkt in die Resourcen der EXE einbinden, so dass ich immer nur die EXE habe, korrekt? Das wär schon mal was.

Wenn das obige geht, könnte das ja dann auch gehen, wenn ich die Wrapper-Methoden der Hersteller-DLL ebenfalls in eine DLL packe, deren Resourcen wiederum die Hersteller-DLL beinhalten => Funktioniert dann [DLLImport] noch, oder muss ich die DLL während der Laufzeit aus den Resourcen rausholen? Ich vermute fast ja, weil [DLLImport] ja eine Datei erwartet, richtig?

Oh je.... Das kann ganz schnell ein ganz schöner Schlamassel werden. Das was du sagst ist zwar alles richtig, aber packe bloß nicht alles in die Resourcen von irgendwas anderem. Du kannst deine DLL (die mit den Chip-Klassen und der Factory) einfach in deiner Anwendung referenzieren. Dann hast du halt 3 Dateien (die .Net-DLL, die native DLL und die EXE). Wenn du das nicht willst, kannst du (was ich aber nicht empfehle) die .Net-Assemblies mit ILMerge zusammen-mergen. Aber was spricht denn dagegen, mehrere Dateien zu haben?

Gruß, Christian.

14.06.2010 - 22:32 Uhr

mal angenommen, das ist tatsächlich so, wäre dann eine abstrakte Chip-Klasse als Basis der "saubere" Weg, oder?

Ja.

Die Seriennummer ist die einzige Information des Devices selbst, um das Device eindeutig zu identifizieren.

Dann sollte das dein Name sein (der String für die Factory).

die ChipInfo-Klasse sollte ja dann eigentlich nur die Informationen enthalten, die den Chip-Typ ausweisen plus die vier o.g. "Identifizierer"

Richtig.

ChipInfo braucht dann nur die Seriennummer, und was es für ein Chip-Typ ist.

Das kannst du als enum machen:

public enum ChipType {
    Normal,
    Special,
    SuperSpecial
}

public class ChipInfo {
    public string Serial;
    public ChipType Type;
    internal Chip Chip;
}

Dann musst du noch die CreateChip-Methode anpassen:

private static Chip CreateChip(ChipInfo info) {
    switch (info.Type)
        case SuperSpecial:
            return new SuperSpecialChip(info);
        case Special:
            return new SpecialChip(info);
        case Normal:
            return new NormalChip(info);
}

Gruß, Christian.

14.06.2010 - 18:50 Uhr

Wobei sich mir hier die Frage stellt, ob ein Chip-Objekt wissen soll/darf/kann, welche anderen Chips am System sind?

Definitiv nein.

  • Die ChipFactory ist statisch, um zu verhindern, dass Objekte dieser Klasse erzeugt werden können und somit evtl. inkonsistente Daten vorhanden sind und ausserdem nur eine Klasse die Chip-Objekte erzeugen kann?

Richtig.

  • müsste die Chip-Klasse nicht abstract sein, um zu verhindern, dass Objekte dieser Klasse erzeugt werden können?

Nein. Aber der Constructor von Chip ist internal --> nur die Factory kann Instanzen erzeugen (jedenfalls wenn du alles was mit der Chip-Erzeugung zu tun hat (und nur das!) in eine seperate Assembly packst; Alles andere (Logik, UI) sollte jeweils sowieso in eine eigene andere Assembly).

  • die Zugriffsmodifizierer internal machen die enthaltenen Objekte für die ganze Assembly sichtbar. Das heisst, um das ganze "richtig" zu machen, müsste ich eine separate Assembly verwenden, ist das korrekt?

Genau (siehe oben).

Ist das beim FactoryPattern üblich, dass die kleinste Produktklasse als Basis dient?

Jein. Wenn du sagen wir mal einen SuperSpecialChip hast, musst du den von SpecialChip ableiten und in der ChipFactory die CreateChip-Methode anpassen, damit bei entsprechenden Werten in der ChipInfo ein SuperSpecialChip erzeugt wird.

Der jetzige Beispielcode macht dann Sinn, wenn die Klasse Chip gleichzeitig dem "kleinsten" möglichen Chip entspricht. Ist das beim FactoryPattern üblich, dass die kleinste Produktklasse als Basis dient? Der andere Weg wäre m.E. nur die gemeinsamen Eigenschaften festzulegen, ob es ein oder mehrere Ports sind, ist ja dann bereits ein Unterschied.

Jein. Die ChipInfo-Klasse ist die Menge aller möglichen Eigenschaften aller Chips. Die Chip-Klasse entspricht tatsächlich dem kleinsten möglichen Chip. Für alle spezialisierten Chip-Arten musst du dir eine eigene Klasse erstellen, die sich aus der assoziierten ChipInfo nur die für sie speziell benötigten Informationen herausholt.

Zusammenfassend:

Du musst für jede mögliche Art von Chip eine eigene Klasse erstellen (Chip, SpecialChip, SuperSpecialChip). In der ChipFactory liest du dann die erforderlichen Daten aus dem System aus. Sagen wir mal, du erfährst hier, es gibt einen "normalen" Hardware-Chip Normal1, einen "speziellen" Special1 und einen "superspeziellen" SuperSpecial1. Dann erstellst du dir die entsprechenden ChipInfo's. Somit ist die ChipFactory erstmal fertig. Wenn du dann in deiner Anwendung den Chip SuperSpecial1 benutzen möchtest, holst du ihn dir einfach aus der Factory (mittels ChipFactory.GetChip("++SuperSpecial1++&quot;)). Diese kümmert sich dann um die Objekt-Erstellung und geht sicher, dass du pro reellem Hardware-Chip nur eine Instanz von Chip hast (kann dann ja auch eben ein SuperSpecialChip sein). Mit dem Chip, den du zurückbekommst, kannst du dann arbeiten. Wenn du dann die super-speziellen Methoden & Eigenschaften brauchst, musst du natürlich den zurückgegebenen Chip auf SuperSpecialChip casten.

Gruß, Christian.

// Edit: noch mehr "Viele Viele bunte Edits"

13.06.2010 - 11:49 Uhr

Hi, Locutus.

Ich würde hier ein angepasstes Factory-Pattern verwenden.

In etwa so (PseudoCode):

namespace MyChips {
    internal class Util {
         // Hier deine Win32 Methoden aus der Dll
    }

    public class ChipInfo {
        public int[] Ports;
        public bool IsMultiPort;
        public SoWieSo SonstWas;
        public WasWeis Ich;
        internal IntPtr Handle;
        internal Chip Chip;
    }

    public class Chip {
        private IntPtr Handle;
        private int Port;
        internal Chip(ChipInfo info) {
            Handle = info.Handle;
            Port = info.Ports[0];
        }
        public virtual void TuWas(string s) {
            Util.Send(Handle, Port, s);
        }
    }

    public class MultiPortChip : Chip {
        private int[] Ports;
        internal MultiPortChip(ChipInfo info)
            : base(info) {
            Ports = info.Ports;
        }
        public override void TuWas(string s) {
            foreach (int port in Ports) {
                Util.Send(Handle, port, s);
            }
        }
    }

    public static class ChipFactory {
        private Dictionary<string, ChipInfo> Chips;
        static ChipFactory() {
            // Alle möglichen Chips auslesen und ihnen Namen geben und sie in Chips speichern
        }
        public static string[] Names {
            get { return Chips.Keys.ToArray(); }
        }
        public static ChipInfo GetInfo(string name) {
            if (Chips.ContainsKey(name)) {
                return Chips[name];
            }
            throw new InvalidChipNameException();
        }
        public static Chip GetChip(string name) {
            if (Chips.ContainsKey(name)) {
                if (Chips[name].Chip == null) {
                    Chips[name].Chip = CreateChip(Chips[name]);
                }

                return Chips[name].Chip;
            }
            throw new InvalidChipNameException();
        }
        private static Chip CreateChip(ChipInfo info) {
            if (info.IsMultiPort)
                return new MultiPortChip(Chips[name]);
            else
                 return new Chip(Chips[name]);
        }
    }
}

Gruß, Christian.

// Edit: Viele viele bunte Edits

12.06.2010 - 17:45 Uhr

"Ins Ausgabeverzeichnis kopieren" --> "PreserveNewest"

Gruß, Christian.