Laden...

Forenbeiträge von Jabberwocky Ingesamt 42 Beiträge

17.03.2006 - 15:26 Uhr

Die Laufvariable bei foreach darf man nicht ändern, soweit richtig.
Den Inhalt sehr wohl, das machst du bei Klassen sicher ständig. Auch in dem Beispiel wird das mit einer Klasse gemacht.
Und es wird mit einem Struct versucht. Beim Struct schlägts aber fehl. Warum nur beim struct und nicht bei class?

17.03.2006 - 15:16 Uhr

Wie erklärst du das foreach Beispiel?

Er versucht s einen neuen Wert zuzuweisen, obwohl ich nur den Inhalt verändert habe.

17.03.2006 - 15:10 Uhr

class TestClass
{
    public int Value;
}

struct TestStruct
{
    public int Value;
}

class Programm
{
    static void Main()
    {
        TestClass[] array1 = new TestClass[]{ new TestClass() };
        TestStruct[] array2 = new TestStruct[]{ new TestStruct() };

        foreach( TestClass c in array1 )
            c.Value = 5;

        foreach( TestStruct s in array2 )
            c.Value = 5;
    }
}

Wertetypen sind prinzipiell imutable. Genau dieses verhalten ahmt string nach. Selbst wenn die Übergabe prinzipiell per Referenz funktionieren würde, und ref immer eine Referenz auf eine Referenz übergeben würde (so wie es eben beim String Typ passiert), hast du durch die Unveränderbarkeit exakt das gleiche Verhalten wie im Moment.

Ich bestreite ja garnicht, dass es hinter dem Code unterschiede gibt. Nur wenn man das Verhalten des ref keywords diskutiert, sollte man auch nur das Verhalten betrachten.

17.03.2006 - 13:56 Uhr

Nein, Wertetypen und Referenztypen werden in diesem Aspekt genau gleich behandelt.

Nur gibt es bei Wertetypen keine Änderungen, sie sind unveränderbar und werden deswegen immer neu zugewiesen wenn du etwas "änderst". Deswegen kommen Änderungen nicht Auße an, es gibt sie nämlich nicht.

Das ist der einzige Unterschied und der hat nichts mit dem ref keyword zu tun.

Mir ist klar, dass unter der Haube ein Wertetyp als Kopie übergeben wird. Aber selbst wenn nicht wäre genau das gleiche Verhalten zu beobachten, das ist mein Punkt. Siehe die string Klasse.

Versuche z.B. mal ein foreach über ein Array von structs und "ändere" das struct. Hier wird dir genau dieses Verhalten auf die Füße fallen.

17.03.2006 - 13:46 Uhr

IsBackground sorgt lediglich dafür, dass die background Threads automatisch beendet werden, wenn es keine foreground Threads mehr gibt. Sprich wenn deine Anwendung beendet wird.

Ich glaube immernoch dein Algorithmus ist fehlerhaft.
Es gibt nur 2 Gründe um überhaupt Threads anzulegen:

  1. Asynchrone Ein-/Ausgabe. Dazu reicht ein Thread pro Ein-/Ausgabe, manchmal auch weniger. So kann man mit einem Thread z.B. mehrere Sockets abfragen.
  2. Parallele Verarbeitung. Das aber auch nur solange du weniger Threads als Prozessoren hast.

Zumal die vielen Threads ein ordentliches Profiling recht schwer machen.
Von ner theoretischen Laufzeitanalyse mal ganz zu schweigen.

17.03.2006 - 13:18 Uhr

Der Performanceverlust ist nur durch schlecht angepassten Code zu erklären.
Dein Code ist dafür gemacht eben mit 3000 Threads zu arbeiten und nicht ohne weiteres auf 20 Threads zu übertragen.

Oder um es anders zu formulieren: Du hast ein Dreieck gebaut, setzt dies nun in eine Viereckige Form, und wunderst dich, dass es wackelt.

17.03.2006 - 12:41 Uhr

Original von Cord Worthmann
Alleinig die ref Anweisung würde entscheiden, ob Parameter "überschreibbar" oder nur "benutzbar/veränderbar" wären - die Adressierungsfrage wäre jedoch einwandfrei geklärt.

Ähm, genauso ist es doch im Moment.
Ohne ref kannst du nur benutzen/verändern, nur mit ref kannst du überschreiben. Egal ob Wertetyp oder Referenztyp.

17.03.2006 - 12:02 Uhr

Eigentlich wenn du die Daten gleich in ne DataTable lädst, und diese dann per Remoting verschickst, kümmert sich der HttpChannel darum, dass es in XML übersetzt wird, und auf der anderen Seite zu einer DataTable zusammengebaut wird.

17.03.2006 - 11:48 Uhr

Objekt ist eben eine Klassifizierung. Du hast doch selbst definiert was es ist. Wenn du Objekt sagst, bezeichnest du damit einen ganz speziellen Gegenstand, so wie wenn ich "mein PC" sage? Nein, du beschreibst eine Gruppe von Gegenständen mit gleichen Eigenschaften.
Ich versteh echt nicht was du willst.

Wie kannst du etwas Objekt nennen, und gleichzeitig sagen es ist nicht vom Typ Objekt?

Da wäre nichts sauberer dran wenn du dir irgendwelchen Quatsch ausdenkst.

17.03.2006 - 00:13 Uhr

Eine Klasse ist eine Beschreibung. Und Object beschreibt eben alle Objekte.
Ich find daran nichts seltsam.
Genauso wie "Objekt" eine Klasse sein kann, kann auch eine Klasse ein Objekt sein, es hängt eben vom Kontext ab.

Ist eigentlich schon jemand auf die Idee gekommen "Gegenstände und Sachverhalte" als die Objekte in dem Zitat, und sowohl "Abbild" als auch "Urbild" als eine Beschreibung einer Gruppe von Objekten, also als Klassen zu sehen?

Konnte nicht allem so ganz folgen was hier verfasst wurde 😉

16.03.2006 - 18:05 Uhr

Der Algorithmus ist mir aber auch spontan eingefallen.

Aber ich glaube es geht etwas besser:

  1. Suche Zeile im Dictionary, wenn vorhanden nehme nächste Zeile
  2. Zeile in zwei Strings A (vorne) und B (hinten) am letzten '' der Zeile trennen
  3. B auf Stack packen
  4. A im Dictionary suchen (= Eintrag) -> falls nicht vorhanden, setze Zeile := A, gehe zu 1
  5. Element vom Stack Runternehmen (=X)
  6. setze X.Parent := Eintrag
  7. Setze Dictionary["Eintrag\X"] := X
  8. Falls Stack leer, betrachte nächste Zeile, sonst gehe zu 4.

Unter der Bedingung dass "C:\A" auf jeden fall in der Liste ist, wenn "C:\A\B" in der Liste ist, müsste er in der Anzahl der Zeilen linear sein... oder behauptet jemand das Gegenteil? 😉

16.03.2006 - 17:40 Uhr

herbivore dein Algorithmus ist O(n²) im worst-case und Linear im best-case

Dein Algorithmus macht in einer Zeile mit k '' Zeichen k Iterationen.
Im Worst-case kommt mit jeder Zeile ein '' dazu
Also hast du im Worst-case 1 + 2 + 3 + ... + n Schritte, was O(n²) ist

bzw. ist es n² in der Anzahl der Zeilen, und linear in der Anzahl der '' 😉

16.03.2006 - 12:18 Uhr

Bei GetValue bezeichnet der erste Parameter das Objekt, von dem du den Wert der Property wissen willst. Oder null bei statischen Properties.
Dort gehört "regs" statt "p.Name" rein.

16.03.2006 - 11:50 Uhr

Auch hier ist die Antwort wieder Invoke

Damit übergibst du eine Methode an den Thread, zu dem das Control gehört. Kannst auch die Nachricht als Parameter übergeben.

16.03.2006 - 02:19 Uhr

Ich dachte bei der Überschrift kommt ne Frage zu DataBindings, tatsächlich ist aber die Antwort "DataBindings" 😉

Jedes Control hat ne Property DataBindings.
Damit kannst du eine Property dieses Controls mit einer Property (oder Feld) eines Objekts oder eines Listenelements, DataSet-Eintrags usw. verbinden.
Dann wird z.B. beim Validated Event des Controls der Wert der Property automatisch auf das Objekt übernommen (kann man auch etwas anders einstellen)

Siehe Binding Klasse

Im Prinzip musst du dafür nur z.B.:

cityTextBox.DataBindings.Add( "Text", address, "City" );

Wie gesagt muss "City" einfach eine Property von der Klasse Adresse sein damit das geht. Text ist eben die Text Property der TextBox, und address das Objekt vom Typ Adresse.

Das funktioniert auch mit selbstgebastelten Properties deines UserControls. Damit lässt sich dann auch komplexeres machen.

Ein kleines "Aber":
Ich glaube nicht, dass die DataBindings schauen, ob sich was geändert hat. Zumindest bei meinen Tests hatte ich den Eindruck als ob sie immer wenn das Validated Event auftritt (also beim simplen Verlassen der TextBox z.B.) den Wert einfach neu eintragen.

15.03.2006 - 17:40 Uhr

Never change a running system.

Wenn du keine Probleme mit dem Aktuellen hast, fällt mir auch kein Grund ein auf XML umzusteigen.

XML lässt sich halt in .NET sehr gut bearbeiten. Man kann per XPath gezielt auf Werte zugreifen, man kann Hierarchien anlegen, und man kann einfach de-/serialisieren.

15.03.2006 - 12:51 Uhr

Auf der BindingSource gibt es die Methode GetItemProperties()
Damit bekommst du ne Liste von PropertyDiscriptor Objekten.
Und bei so nem PropertyDiscriptor gibts einmal die Felder "Name" und "DisplayName"
Und es gibt die Funktionen "GetValue" und "SetValue", denen du das Current Objekt der BindingSource übergibst.

Denke so sollte das klappen

15.03.2006 - 12:38 Uhr

Also ich mach das im Moment über Remoting. Gibt es denn da noch ne andere Möglichkeit?

14.03.2006 - 18:10 Uhr

Original von herbivore
Hallo zusammen,

ich denke es ist alles andere als ein Syntax-Problem. Ich halte es für ein technisches Problem. Wenn sich Properties bei out Parametern genauso verhalten würden, wie bei Feldern, wäre das Problem m.E. schon gelöst (und das wäre durchaus technisch möglich).

Das Problem ist gelöst wenn man Properties als das betrachtet was sie sind:
Funktionen mit einem vereinfachten Aufrufsyntax

Dann passt plötzlich alles.

14.03.2006 - 16:38 Uhr

Suchprobleme sind immer auch Sortierprobleme.
Suchen in unsortierten Arrays ist immer nur in linearer Laufzeit möglich, da gibt es nichts besseres als vorne anfangen und bis hinten durchsuchen.
Das zweite wäre ne Binäre Suche. Die kommt hier glaub ich kaum in Frage, denn dafür müsste ne > Relation bekannt sein. Wüsste nicht auf welchen Wert du das anwenden willst. Die geht in logarithmischer Zeit. Musst aber vorher Sortieren. Also imo in der Größenordnung von der wir reden kaum besser als lineare Suche.
Das dritte wäre ne Suche mit nem HashCode, wie bei ner HashTable oder Dictionary. Die sollte fast in konstanter Zeit gehen.

Das Einfachste wäre, wenn du einfach eine List<DirectoryInfo> erzeugst und per AddRange( ... ) füllst.
Dann hast du ne Contains Funktion, aber die wird nicht besser sein als lineare Suche (siehe oben).

Meine zweite Idee wäre ein Dictionary<string,DirectoryInfo>. Die Contains Methode sollte doch deutlich schneller sein:

Dictionary<string,DirectoryInfo> dict = new Dictionary<string,DirectoryInfo>();
			
foreach( DirectoryInfo info in directoryArrayB )
{
	dict.Add( info.FullName, info );
}
			
foreach( DirectoryInfo info in directoryArrayB )
{
	if( dict.ContainsKey( info.FullName ) )
	{
		...
	}
}

14.03.2006 - 16:22 Uhr

Sowas?

(Ich hab nicht getestet was da raus kommt)

14.03.2006 - 11:58 Uhr

Original von Der Eisbär
Beziehungsweise, wie müsste ein Objektmodell (oder besser gesagt -paradigma) aussehen, um diese Problematik zu umgehen?

Diese Problematik hat mit nem Objektmodell nichts zu tun sondern nur mit nem Syntax. Der Syntax ist eben "property = value;", aber eben nichts anderes als set_property( value );". Das ist eben nur ein Syntax wie du diese Funktion aufrufst. Siehe zum Beispiel die decompilierte Fassung, wo genau diese Funktionen dann drin stehen.
So wie du mit nem Operator eine Funktion aufrufst, die aber nicht nach nem Funktionsaufruf aussieht.

Befassen sich Objektmodelle mit Syntaxproblemen?
Properties sind nichts besonderes, sie sind nur ein vereinfachter Syntax für ganz bestimmte Funktionen, nämlich getter und setter. Bzw. adder und remover bei events 😉

13.03.2006 - 22:30 Uhr

Also rein formal definiert bilden alle Felder der Klasse den Zustand, und Properties sind Ausgabefunktionen, die vom Zustand abhängen oder Eingabefunktionen, die den Zustand ändern.

Siehe zum Beispiel Moore-Automat, oder noch besser, Turing-Maschine 😉

Man kann eine Klasse eigentlich parallel zu nem Automaten definieren:
Eine Menge an Zuständen
Zustandsübergangsfunktionen
Ausgabefunktion

Es ist da schon richtig, dass Properties und Funktionen in die gleiche Kategorie gehören.
Ich seh nur irgendwie das Problem das daraus erwächst nicht so richtig.
Nur weil sie syntaktisch wie Felder aussehen ist das eine Schwäche?

Was soll man denn bitte zu Delegates sagen? Mal wie ein Feld mal wie ne Funktion.
Daraus erwächst aber kein Problem, weil es wohldefiniert ist.

13.03.2006 - 21:43 Uhr

Danke für den Hinweis, hat mich zu nem neuen (viel besseren 😄) Lösungsansatz gebracht.

Hab jetzt umgebastelt auf Parameter.
Mir hat es nur etwas Probleme bereitet, wenn ein Wert bei nem Befehl mit WHERE NULL war.

Wie etwa in der Art:

DELETE FROM [Data1] WHERE [ID] = @p0 AND [Data2_ID] = @p1

Wie gesagt soll das ne Vereinfachung für Datenbankoperationen werden, also er sollte den String automatisch zusammenstellen und für mehrere Zeilen benutzen können. Wenn aber der Wert von @p1 jetzt DBNull ist, findet er nicht den passenden Eintrag.

Gelöst hab ich das, indem ich für jeden Parameter der NULL annehmen kann auch noch einen extra Parameter angelegt habe, dass am Ende sowas rauskommt:

DELETE FROM [Data1] WHERE [ID] = @p0 AND ( ([Data2_ID] = @p1) OR (@p2 = 1 AND [Data2_ID] IS NULL) )

Beim Übernehmen der Werte einer Zeile in die Parameter des Commands wird dann @p2 auf 1 gesetzt, wenn @p1 den Wert DBNull zugewiesen bekommt.

Erste Tests hat das bestanden.

Nur so für nachfolgende Generationen die auch sowas machen wollen 😁

13.03.2006 - 21:34 Uhr

Naja wenn du es erstmal auf ne Variable zugewiesen hast geht das mit anonymen Delegates genauso wie mit jedem anderen:

Kleines Beispiel:

Action<string> d = delegate( string text ) { Console.WriteLine(text); };
d.BeginInvoke( "test", null, null );

Anonyme Delegates sind nur beim Invoke von Controls etwas unhandlich.

Interessanterweise geht z.B. das:

System.Threading.Thread t = new System.Threading.Thread( delegate() { Console.WriteLine("test"); } );

Aber das nicht:

this.Invoke( delegate() { MessageBox.Show("test"); } );

Mit Fehlermeldung "cannot convert from 'anonymous method' to 'Sytem.Delegate'"

Aber dafür das:

System.Threading.ThreadStart d = delegate() { MessageBox.Show("test"); };
this.Invoke( d );

Sprich anonyme Methoden werden automatisch in bestimmte Delegate-Typen umgewandelt. Delegate-Typen werden implizit in System.Delegate umgewandelt. Aber anonyme Methoden werden weder explizit noch implizit in System.Delegate umgewandelt. Erklären kann ich mir das nicht...

13.03.2006 - 19:54 Uhr

Original von svenson
IntPtr als Rückgabewert ist richtig. Da der Encoder aber sicherlich binär arbeitet, ist das Ergebnis byte[]. Statt PtrToStringAnsi() also Marshal.ReadByte(i, argC).

Ich würde davon ausgehen, dass auch die Eingangsdaten binär sind (auch hier wird eine Längeninfo verwendet), daher:

Also dass String für const char* und StringBuilder für char* klappt, dafür leg ich meine Hand ins Feuer. Das hab ich schon öfters getestet. Das Framework kümmert sich darum, dass die richtigen Daten ankommen. Man kann auch festlegen ob der Text Unicode oder Ansi ist, etc. Siehe den von mir gelinkten Artikel.

Nur mit Rückgabewerten hab ich keine Erfahrung. Bei dem was ich bisher gemacht hab kam die Rückgabe über nen Parameter und das return value war ein Error-Code (int)

IntPtr hab ich bisher nur für Handles aller Art benutzt...

13.03.2006 - 19:46 Uhr

Ok als erstes mal was du falsch machst:

  • wie schon gesagt wenn du Join auf einen Thread aufrufst, wartest du bis er beendet ist. Von paralleler Ausführung kann da keine Rede mehr sein.
  • prinzipiell Abort vermeiden wo es nur geht. Threads möglichst normal auslaufen lassen, indem die ThreadStart Funktion zu nem Ende kommt.
  • Auf source_pfad_parameters wird von 2 Threads aus zugegriffen. Da bei dir nichts parallel ausgeführt wird ergibt das keinen Fehler, aber bei sowas sollte man immer aufpassen. Wenn du z.B. wie vorgeschlagen nur das Join weglässt können durchaus Werte verloren gehen, weil der eine Thread schon nen neuen Wert einträgt, bevor der andere den Wert gelesen hat. Prinzipiell wenn es um Threads geht kann man sich auf Zeitablauf nicht verlassen, wenn man darauf angewiesen ist, muss man es per WaitHandle oder lock(...) garantieren.
  • ein Problem bei deiner Lösung, wenn man Join weglassen würde wäre außerdem, dass da eine unbestimmte Anzahl an Threads erstellt wird. Man sollte die Zahl der Threads immer möglichst niedrig halten, da durch jeden Thread ein Overhead produziert wird, sodass bei ner großen Anzahl Threads die Performance deutlich nachlässt. Ich glaube es gibt sogar ne maximale Anzahl die man erstellen darf...

Die Lösung:
Als erstes mal definiere das Problem.
Wenn ich dich richtig verstanden habe ist dein Problem ja lediglich, dass das GUI hängen bleibt. Die Aufgabe ist also nur möglichst schnell den GUI Thread wieder freizugeben.
Dafür reicht ein Thread völlig.
Du schiebst die Funktion asynchron an, änderst den Status der GUI (neue Eingaben verhindern z.B.), und lässt einfach laufen. Damit ist die Aufgabe in dem Thread schnell erledigt und das Programm sieht nicht so aus, als hätte es sich aufgehangen.

Das sieht dann so aus (für den fiktiven Knopf ButtonStart der das anschieben soll. Kann gerne sonstwo anders stehen):

void ButtonStart_Click( object sender, EventArgs e )
{
    buttonStart.Enabled = false; // damit es nur 1 mal gleichzeitig läuft

    Action<string> method = install_XP_Standart;
    // Der erste Parameter ist das, was du an die Funktion übergeben willst
    // hab mir da jetzt einfach was ausgedacht
    method.BeginInvoke( eingabe, null, null); 
}

Das wars auch schon. Man kann zwar noch etwas verbessern, aber ich finde so reichts erstmal 😁
Durch BeginInvoke wird die Funktion in nem eigenen Thread ausgeführt. Dazu muss man erst nen Delegate anlegen, in dem Fall hab ich einfach den Generic Action<T> genommen, kann alles mögliche mit beliebigen Parametern sein. Dann streichst du alles was mit Threading zu tun hat aus der Funktion install_XP_Standart raus. Die Funktion patch_install kannst du entweder löschen und die paar Zeilen in die Schleife schreiben, oder du rufst sie direkt auf. Aber bitte mit echten Parametern für source_pfad_parameters und source_pfad 🙂

Das Einzige was dann nicht klappen wird ist das mit den listBox1.Add( ... ), weil wie gesagt man sollte Formulare in ihrem eigenen Thread verändern. Dazu gibt es aber eine Lösung durch Invoke. Und das sieht dann so aus:

Zuerst müssen wir mal ne Funktion anlegen. Ich mach es mal so, wie es bei mir meist aussieht. Ich sorge in der Funktion selbst dafür, dass sie im richtigen Thread ausgeführt wird. Hat jetzt keine großartigen Vorteile oder nen speziellen Grund... außer dass es man sich die Invoke Arbeit nur einmal macht und die Funktion dann von wo man will ganz normal aufruft.

void listBox1_AddItem( string text )
{
    if( listBox1.InvokeRequired ) // wir sind in nem anderen Thread
    {
        // ich erzeuge nen passenden Delegate
        // und übergebe diesen und alle Parameter an .Invoke
        // damit wird es an den richtigen Thread übergeben und ausgeführt
        listBox1.Invoke( new Action<string>( listBox1_AddItem ), text );
        // das war alles was wir in diesem Thread machen wollten, also return
        return;
    }

    // das hier wird ausgeführt, wenn die Funktion im richtigen Thread aufgerufen wird
    listBox1.Items.Add( text );
}

Damit wär auch das erledigt.
Musst dann in der install_XP_Standart Funktion eben die listBox1_AddItem Funktion aufrufen, statt selber listBox1.Items.Add aufzurufen.

Man kann das auch mit anonymen Delegates machen, so dass man keine Funktion anlegen muss. Aber ich denke so ist es erstmal übersichtlicher oder?

Wie du den Knopf wieder enablest kriegst du hoffentlich selbst raus 😉
Schau auch mal bei MSDN zu Delegate.BeginInvoke um zu sehen, was damit noch alles geht (wie z.B. die angesprochene AsyncCallback)

PS das ganze ist jetzt aus dem Gedächtnis geschrieben. Kann durchaus vorkommen, dass ein paar Details falsch sind. Ich hoffe die anderen Könner lesen mit! 😉

13.03.2006 - 16:14 Uhr

Ich bastel momentan an etwas, das mir die Arbeit mit einer SQL Datenbank etwas verkürzen soll.

Das mitgelieferte System.Data ist mir an manchen stellen zu aufwändig zu benutzen, und da ich einige Funktionalitäten öfters brauche schreibe ich ein paar Shortcuts.

Ich bin da im Moment auf ein kleines Problemchen mit der Formatierung gestoßen. Der SQL Server erwartet meist ein anderes Format als .ToString() ausspuckt, also wollte ich mit Convert.ToString( object, CultureInfo ) arbeiten.
Im Großen und Ganzen funktioniert das auch ganz gut mit der Culture "en-GB".
Scheinbar einziges Problem: Booleans gibt es nicht, er erwartet statt true und false 1 und 0

Gibt es vieleicht irgendwo eine CultureInfo, mit der ich auch dieses Problem los werde?
Es ist keine große Sache Booleans rauszufiltern, aber ich wollte mal rumfragen, ob vieleicht jemand ne clevere Lösung für sowas parat hat.

Übrigens, warum ich den SqlDataAdapter nicht benutze, damit lassen sich keine Views updaten. Und genau das brauche ich jedoch an ausgewählten Stellen.

13.03.2006 - 15:40 Uhr

Start() gefolgt von nem Join() ist einfach das sinnloseste was man mit Threads machen kann.
Du startest ihn und wartest dann, dass er beendet. Da hättest du die Funktion auch gleich direkt aufrufen können, hat genau die gleichen Auswirkungen.

Ich sehe was du machen willst, das ganze ist wirklich nicht so einfach zu lösen...

Ich muss hier noch etwas arbeiten sonst würde ich ausführlicher werden...
Aber es gibt so viel was mit deiner Funktion nicht stimmt...

Als schnellen Hinweis, such mal nach Delegate.BeginInvoke. Damit führst du eine Funktion asynchron aus ohne die Threads handhaben zu müssen. AsyncCallback ist eine Funktion die aufgerufen wird, wenn die Funktion im Delegate beendet wurde. Sprich die stelle wo du in die listBox schreibst.

13.03.2006 - 01:10 Uhr

Könntest es ja mal mit char[] als Rückgabewert versuchen und schauen was du da für ne Länge bekommst. Ich vermute auch es wird wegen \0 aufgehört.
könntest dann durchiterieren und alle \0 durch \n oder so ersetzen, und dann mit dem String Konstruktor umwandeln.

12.03.2006 - 19:15 Uhr

Hast recht, er ist als Klasse definiert.

Hab mich davon täuschen lassen, dass er sich in so ziemlich allen mir bekannten Belangen wie ein Wertetyp verhält.
So liefert er immer eine neue Instanz wenn er verändert" wird.
Woraus folgt, dass er sich auch bei Parameterübergabe anfühlt wie ein Wertetyp.

Die Lehre die man daraus ziehen kann:
Struct ist ne schwächere Definition als class, denn eine class kann das äußere Verhalten eines structs annehmen, aber andersrum ist es nicht möglich.

Ich empfinde das aber trotzdem nicht als eine "Schwäche in C#", das etwas nicht das ist, wofür man es hält.
IntelliSense ersetzt eben nicht Doku lesen, das ist eigentlich der einzige Schluss den man aus den aufgezählten "Schwächen" ziehen kann (wie das mit den Properties z.B. auch)

12.03.2006 - 14:15 Uhr

Hab gerade ein Video von MSDN TV angeschaut und dort benutzt der Typ die Klammern auch auf der gleichen Zeile wie die Funktion/Bedingung 😉

11.03.2006 - 22:54 Uhr

String ist übrigens ein Wertetyp

11.03.2006 - 22:10 Uhr

Das AutoResetEvent bewirkt, dass der Thread der die Funktion "WaitOne" aufruft solange an dieser Stelle wartet, bis ein anderer Thread Set() aufruft.
AutoResetEvent weil es nachdem WaitOne beendet automatisch Reset() aufruft.

Parallele Verarbeitung erledigt man mit Queues, wo die zu verarbeitenden Daten rein kommen und vom verarbeitenden Thread abgeholt werden.
WaitHandles (wie das AutoResetEvent) sorgen für synchronisation zwischen den Threads, also z.B. dass einer wartet bis der andere seine Arbeit erledigt hat.
Damit sollte eigentlich alles machbar sein was du dir da vorstellst.

11.03.2006 - 22:01 Uhr

Benutzen von C/C++ DLLs geht meiner Meinung nach IMMER ohne unsafe code und Verwendung von Pointern in C#

Dazu dieser Artikel auf MSDN

Kurze Zusammenfassung:
Du musst immer einen CLR Typ finden den du als Argument beim DLL Import angibst.
Wenn die C/C++ Funktion Pointer auf einen Datentyp erwartet, definiere den entsprechenden Parameter mit "ref" oder "out" keyword.
Speziell bei Zeichenketten: Wenn es ein konstanter Pointer auf eine Zeichenkette ist, also nur als eingabewert dient, benutze den CLR Typ string, ansonsten wenn er auch zur Ausgabe benutzt wird den StringBuilder.
Wie es sich da mit dem eigentlichen Rückgabewert via return verhält weiß ich nicht, ich vermute aber string sollte da in Ordnung gehen, da er ja komplett in der C-DLL angelegt wird.

Steht alles da drin ausführlich erklärt. Angewendet auf dein Beispiel ergibt das folgenden Code:

[DllImport("TestLib.dll")]
public static extern string testFunc(StringBuilder argA, StringBuilder argB, out int argC);

Wenn argA und argB nicht in der C Funktion verändert werden müsstest du auch ganz normal string benutzen können... aber auch ohne Garantie 😉

Außerdem lohnt sich gerade bei dem Thema ein Blick auf SharpDevelop.
Dort gibt es unter Extras "P/Invoke Signatur einfügen..." wo du die DLL und Funktionsname angibst, und er sagt dir die C# Definition der Funktion.

11.03.2006 - 18:52 Uhr

Witzigerweise arbeite ich im Moment an einem Gruppenprojekt und es macht da irgendwie keinem was aus, dass ich Pascal-mäßig klammere und ein anderer nicht.

Dass man sich bei der Notation auf was einigen muss und nicht wild durcheinanderwürfelt ist mir ja noch klar.
Aber wen das ernsthaft so sehr stört, dass die Klammern nun auf der gleichen Zeile oder auf der nächsten sind, dass es seine Arbeitsweise stört... ist eher ne Zwangsneurose als ein Problem am Code

11.03.2006 - 17:10 Uhr

Das Problem sind Zeilen wie diese:
float factor1 = (pImage.Width/pHSize);

Es wird sich immer nach dem linken Operanden gerichtet. Da dieser ein Integer ist, wird die Integer-Division benutzt. Die hat immer einen Integer als Ergebniss. Sprich das was hinterm Komma steht ist schon vor der Zuweisung von factor1 weg, da hilft auch kein Cast zum Float mehr.

Die Lösung ist also den linken Wert der Division in einen Float zu casten:

float factor1 = ((float)pImage.Width) / pHSize;

Da der linke Wert jetzt ein float ist, wird die float-Division ausgeführt mit einem float als Ergebniss.

Kleines Beispiel:
Was bei dir im Moment passiert:
Console.WriteLine( (float)(5 / 2) ); // Ergebnis wird gecastet
Wie es richtig wäre:
Console.WriteLine( (float)5 / 2 ); // linker Operand wird gecastet

Der rechte Operand wird dabei implizit auf den Typ des linken gecastet (afaik)

Ich kann nicht versprechen, dass damit richtige Ergebnisse rauskommen, aber es ist zumindest der Rechenfehler der mir auffällt 😉

11.03.2006 - 16:25 Uhr

Da gibt es recht viele Ansätze...

Das Erste wäre wie du schon sagtest das Objekt auf seinen echten Typ casten und die Werte die du wissen willst auslesen, bzw. eintragen

Alternativ dazu kannst du aus dem DataGrid.SelectedRows[0].Cells[...].Value die Werte auslesen/eintragen.
Das ist geht glaub ich für dein Problem am Besten. Am DataGrid kannst du sowohl die Werte, als auch die "Feldnamen" direkt und dynamisch auslesen, ohne viel zu casten (bei den Value müsstest du vieleicht ToString() aufrufen) bzw. ohne Reflection.

Und du kannst die BindingSource direkt mit der TextBox.Text Property verbinden:

nameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", deineBindingSource, "Name" ) );
vornameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", deineBindingSource, "Vorname" ) );

Das würde jedoch nur jeweils einen Wert pro TextBox erlauben.
Es geht zwar auch deutlich besser/komplexeres, indem man z.B. eigene Properties mit get&set anlegt und Bindet aber das übersteigt denk ich das Problem 😉

Siehe auch hier

11.03.2006 - 13:55 Uhr

Original von FZelle
Du weist, das MS für C# die Pascal version der Klammerung bevorzugt?

Also das gehört nun wirklich zu den Dingen, die jeder Programmierer halten kann wie er lustig ist. Wer Code nicht versteht weil die Klammer auf ner anderen Zeile ist als er erwartet, sollte lieber Socken verkaufen statt zu programmieren...

11.03.2006 - 13:13 Uhr

Auch wenn ich mich hier als Leichengräber betätige möchte ich noch anmerken, dass man "wirklich mächtige Lösungen" mit SettingValueElement hinkriegen kann. Der Inhalt des Knotens wird direkt als XML gespeichert und kann daher später in Laufzeit dynamisch ausgewertet oder auch serialisiert werden.
Das benutze ich zur Konfiguration meiner Plugins.

11.03.2006 - 12:46 Uhr

Also ich würde sagen es gibt da zwei Wege etwas in der Art zu erreichen.

  1. Benutze eine Wrapper-Klasse
    Du legst eine neue Klasse an mit den Eigenschaften die du im PropertyGrid sehen willst.
    Dann überträgt du irgendwie die Werte auf das Objekt das du eigentlich editieren wolltest.
    Entweder du überträgst bei nem Event auf das echte Objekt, oder du lässt die Properties der neuen Klasse direkt auf die Properties des echten Objekts zugreifen.

Nicht unbedingt eine wunderschöne Lösung, aber sie ist wirksam, simpel und sauber.

  1. Implementiere ICustomTypeDescriptor
    Damit hab ich persönlich noch nicht gearbeitet aber damit sollte man volle Kontrolle über das bekommen, was im PropertyGrid zu sehen ist. Siehe dazu vieleicht hier oder hier

Ist denk ich komplizierter und braucht mehr Einarbeitungszeit.

Deine Methode ist natürlich auch eine Möglichkeit, aber mit viel Vorsicht zu genießen. Ein Verbesserungsvorschlag von mir wäre die neuen Properties auf die alten zugreifen zu lassen und nur per Browsable Attribut verstecken:


[Browsable(false)]
public new Object Tag
{
  get { return base.Tag; }
  set { base.Tag = value; }
}

Damit beseitigst du einige Fallen in die du später treten könntest