Laden...

Profil von Jabe

myCSharp.de - Member Mitglied seit

Alle Beiträge

Folgendes Muster ist ausreichend, die Engine ist schlau genug um zu erkennen, dass die curly brackets nicht zu einem Quantifizierer gehören.
Der Stern ist ungenau, oder willst du auch "{}"? Beliebig viele Zahlen ist für mich 1 bis n, also das Plus.
\d ist natürlich das gleiche wie [0-9] aber IMHO klarer.

{\d+}

Integer-Operationen sind ganze Zahlen. Du kannst nicht 1 lebende Kuh zwischen 3 Bauern aufteilen.

Klar kann man das, dann hat man eben keine (0) lebende Kuh.

PS: OK der Joke war so gedacht. ^^ brauch nochmal Wochenende

Häufig ist es nicht sinnvoll eine generische Methode zu schreiben und diese dann per Reflection aufzurufen. Oft kann man das gleiche mit object erreichen, ohne viel ändern zu müssen.
Generics sind eine Hilfe für die Compile-Time, d.h. wenn man den Code eintippt. Steht der Typ zu dieser Zeit nicht fest, machen sie wenig Sinn.

PS:
Ausnahmen bestätigen hier natürlich die Regel. 😉

23.08.2008 - 00:19 Uhr

Du kannst LINQ gegen alles benutzen, was IEnumerable implementiert und es ist unglaublich flexibel. Ich könnte mir sowas vorstellen:

var q = from trx in TransactionMonitoring.TransactionList.Values
        where trx.Ended.HasValue
        let duration = trx.Ended.Value - trx.Started
        group duration by trx.Caller;

foreach (var grouping in q)
{
    Console.WriteLine("{0}: {1}", grouping.Key, grouping.Average(x => x.Milliseconds));
}

Median gibt es direkt nicht, du kannst dir aber eine eigene Extension-Method schreiben. Ist nicht sehr schwer.

18.08.2008 - 22:56 Uhr

Das ganze ist wohl hochgekeimt, weil das Entity Framework eben genau den gleichen weg wie diese Bohnen geht. Viele Entwickler würden lieber sehen, dass das EF auch POCOs persistieren kann, was -- AFAIK -- nicht möglich ist.

11.08.2008 - 21:18 Uhr

resharper-standard einstellung.

Dito.

Eingerückt mit 4 Spaces. Früher habe ich immer Tabs genommen, aber mittlerweile bin ich überzeugt, dass Spaces wesentlich praktischer sind.

PS:
Für XML/XAML habe ich mich irgendwie in ein neuen Stiel verliebt, jede Eigenschaft in eine neue Zeile (kann man in VS auch einstellen). Ist allerdings eher exotisch, glaube ich. Das sieht dann so aus:

<Menu x:Name="mainMenu"
      DockPanel.Dock="Top">
    <MenuItem Header="Database">
        <MenuItem Header="Compress"
                  Command="local:Commands.CompressDatabase" />
    </MenuItem>
    <MenuItem Header="Help" />
</Menu>

11.08.2008 - 11:17 Uhr

Hi,
InvokeRequired aus WinForms-Zeiten ist was anderes als der WPF-Dispatcher. Man muss also etwas umdenken. Der Dispatcher verwaltet mehrere Warteschlagen mit unterschiedlichen Prioritäten, und alle Aktionen in WPF werden über ihn abgewickelt. Insofern kann man ihn wunderbar benutzen um kleine Aktionen (oder kleine Häppchen einer großen) auf dem GUI-Thread durchzuführen.
Wenn man nun aus einem richtigen Thread auf die GUI zugreifen will, kann man das auch über den Dispatcher machen:
Man holt sich den Dispatcher der GUI (nicht des Workerthreads, sprich Dispatcher.Current im Worker wird nicht funktionieren) und kann dort seine Aktion per BeginInvoke (oder Invoke) ausführen.

Hi,
es gibt zugar eine Code Metric, also eine Maßeinheit für die Qualität des Codes, die sich nach der Anzahl der gemeinsamen Felder richtet (Lack of Cohesion in Methods). Von daher sollten Methoden, die sich keine Felder der Klasse teilen, in andere Klassen überführt werden oder statisch gemacht werden (viele Hilfsfunktionen sind so). Wenn du nun die lokalen Variablen eine Methode als Felder deklarierst, machst du diese Metric kaputt. 🙂

Sollte eine Variable möglichst auch gleich instantiiert werden

Microsoft.CSharp.CSharpCodeProvider cSharp = new Microsoft.CSharp.CSharpCodeProvider();  

oder sollte die Deklaration und Instatiierung getrennt erfolgen, damit z.B. die Zeilen nicht zu lang werden?

Im Gegensatz zu früher sollte man Variablen erst dann deklarieren und initialisieren wenn man sie braucht. Eine getrennte Deklaration macht man nur dann Sinn, wenn man sie wirklich brauch (häufig sowas wie: int a; if(x) a = 5; else a = 42; a++).
Wenn dir diese Zeile zu lang ist:

using Microsoft.CSharp; // :)
using CSCP = Microsoft.CSharp.CSharpCodeProvider; // Alias für die Klasse
var cSharp = new Microsoft.CSharp.CSharpCodeProvider(); // Mit C# 3 Compiler

und wenn ich richtig liege, dann werden BackgroundWorker in dem Standard ThreadPool gestartet und dieser ist auf 25 Threads "gleichzeitig" beschränkt.

Zur Vollständigkeit: Es sind 25 Threads pro CPU/Core. Ändern kann man das mit ThreadPool.SetMaxThreads().

08.08.2008 - 13:38 Uhr

Jetzt wo du fragst ... Darüber hab ich noch garnicht nachgedacht.
Keine Ahnung, ob Generics bei Valuetypen Boxing auslöst oder nicht.
Da muss ich bei Gelegenheit mal nachforschen (jetzt hab ich leider keine Zeit).

Mir gings genauso. Musste auch erstmal schnell einen kleinen Test machen. 🙂
Wie schon von winSharp93 so halb gesagt:
Die Runtime erzeugt zur Lauftzeit den entsprechenden Code, wenn sie auf einen neuen, noch nicht generierten TType trifft, von daher passiert das auch mit Wertetypen.

08.08.2008 - 11:49 Uhr

Das Dictionary kann nur Referenztypen behandeln.

Quelle? Der Source des Dictionary ist komplett generisch, insofern gibt es kein Boxing. Boxing gibt es nur beim Hashtable.

08.08.2008 - 10:44 Uhr

Ich würde auch nicht System.Drawing.Point benutzen, da

  1. Point ein Value-Type ist und umständliches Boxing nötig ist, um Ihn in einem Dictionary zu verwenden.

Was meinst du? Beim Einfügen interessiert es das Dictionary herzlich wenig ob reference oder value type.

08.08.2008 - 10:24 Uhr

Es gibt wohl zwei Gründe warum noch keiner geantwortet hat:

  1. MVP ist laut seinem Autor "retired".
  2. Man darf das nicht so eng sehen, IMHO. Das Pattern soll schließlich eine Hilfe sein. Richtig ist es, wenn es sich beweist; tut es das nicht: refactor. Auch bei MVC gibt es mehrere Auffassungen und Variationen, zum Beispiel MVVM für WPF. Und auch dazu gibt es viele Diagramme.
04.08.2008 - 15:29 Uhr

Es gibt ein Punkt-Struct: System.Drawing.Point (oder PointF).

Ansonsten kannst du dir auch selbst eins schreiben:

private struct MyPoint
{
    private int x;

    private int y;

    public MyPoint(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public int X
    {
        get { return x; }
        set { x = value; }
    }

    public int Y
    {
        get { return y; }
        set { y = value; }
    }

    public bool Equals(MyPoint obj)
    {
        return obj.x == x && obj.y == y;
    }

    public override bool Equals(object obj)
    {
        if (obj.GetType() != typeof (MyPoint)) return false;
        return Equals((MyPoint) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (x*397) ^ y;
        }
    }

    public static bool operator ==(MyPoint left, MyPoint right)
    {
        return left.Equals(right);
    }

    public static bool operator !=(MyPoint left, MyPoint right)
    {
        return !left.Equals(right);
    }
}

Wichtig ist nur, dass GetHashCode überschrieben ist, da das Struct als Dictionary-Key verwendet wird. Ansonsten leidet die Performance des Dict daramatisch.

Cecil wäre vielleicht auch eine Möglichkeit, siehe deren FAQ.

02.08.2008 - 18:46 Uhr

Eine etwas interessantere Lösung ist auch möglich ohne die Dezimal-Trennzeichen zu entfernen. Das ganze macht die Globalisierung einfacher.
Dadurch ist das Zahlenformat natürlich abhängig vom eingestellten Systemstandard, oder durch eine von Hand eingestellte Kultur.

// Standard
values.Add(long.Parse(token, NumberStyles.AllowThousands));

// feste Kultur für Englisch (also z.B. 305,141,632)
values.Add(long.Parse(token, NumberStyles.AllowThousands, CultureInfo.CreateSpecificCulture("en").NumberFormat));

Allerdings muss man auch hier hin und wieder etwas aufpassen, wie bei Globalisierung allgemein.

01.08.2008 - 18:00 Uhr

Das Problem ist wahrscheinlich weniger, dass es 2 Methoden gibt, die nur diurch Groß- / Kleinschreibung unterschieden werden, viel schlimmer ist die Problematik bei Protected Membervariablen und Public Properties...

Bei Variablen ist das immer so eine Sache, stimmt schon. Für private Variablen Unterstrich oder nicht, bla bla wir kennen die Stories. 🙂 Allerdings kann man mit Me (this) private foo und public Foo in VB unterscheiden, sollte man mal an dem Punkt kommen.

01.08.2008 - 15:08 Uhr

Eine Einschränkung hat das Ganze... VB.NET ist nicht case-sensitive, d.h. eine Methode TEST() und test() können nicht unterschieden werden. Beim Erstellen von VB.NET Code mag das irrelevant sein, versuchst du jedoch eine Assembly einzubinden, die in C# kompiliert wurde und eben genau diese beiden Test() Methoden mitbringt, so kannst du diese nicht in VB.NET aufrufen (keine von beiden).

Wer sowas tut, sollte sich sowieso einen neuen Beruf suchen.

PS:
Case-insensitivity ist eh viel besser. 🙂

Ich nehm alles zurück. Ich hab vermutet, dass ein Dictionary bzw. Hashtable sowas wie einen balancierten Baum intern benutzt um die Values zu finden. Das war aber eine Fehlvermutung. Tatsächlich wird aber anscheinend das Hash direkt mit einer Speicheradresse verknüpft.

Um genau zu sein wird jedes Element einem Bucket anhand des Hashcodes zugeordnet. Ein Bucket ist im Prinzip nichts anders als eine Liste. Wenn man nun sehr ähnliche Hashcodes hat (z.B. durch ein Struct als Key, in dem GetHashCode nicht von Hand überschrieben wurde), landen sehr viele Elemente in einem Bucket und O(1) mutiert zu irgendwas um O(n) (ok das wäre der worst-case, stimmt nicht ganz von der Notierung, das ist bei Dict. sowieso so ne Sache 🙂).
Der Hashcode ist also eine Art Vorauswahl, deswegen funktioniert das Dictionary auch, wenn die Hashcodes alle den gleichen Wert haben, nur dann werden alle Schlüssel per Equals verglichen.

Noch zum Überschrieben von GetHashCode:
Man sollte immer eine Konstante mit reinrechnen, damit die Operation nicht kommutativ ist.
Statt A ^ B also lieber A*42 ^ B.

Der Resharper kocht den Code übrigens so:

public override int GetHashCode()
{
    unchecked
    {
        int result = myMonth;
        result = (result*397) ^ myYear;
        result = (result*397) ^ myDay;
        return result;
    }
}

Das ist übrigens eine Grundproblematik in .Net so dass es keine allgemeingültige Lösung für ein DeepCopy eines beliebigen Objektes gibt.

Serialisieren und dann Deserialisieren. Auf jeden Fall recht allgemein, natürlich nicht sonderlich sauber. 🙂
Deep Copies brauch man eigentlich recht selten, da tut es nicht weh das Interface zu implementieren.

@Jabe: Das mit dem vollen Namen geht leider nicht, da jeder Compiler (C# oder VB oder was weis ich) die Namen der Properties nach belieben vergeben kann, sie müssen nicht so heißen, wie in C#. Das erklärt auch, warum nicht der IL-Name des Typs gilt ('1[[...) sondern der C# Name mit <.

Du beziehst dich sicherlich auf das hier. Habe ich auch gelesen und vermutet. 🙂 In VB stimmt der Name bspw. nicht mehr. Reflection ist hier leider etwas "messy".
Du musst wohl oder übel mit GetProperties herumsuchen (stand das jetzt noch im Raum? Habe ich heute Mittag gar nicht dran gedacht 🙂).

Hi,
ich wusste die Lösung auch nicht, habe mal ein bisschen gesucht, wurde aber nicht wirklich fündig.

Der Trick ist es, GetProperty mit dem vollen Namen aufzurufen, bei einem nicht-generischen Interface wäre das:

var info = t.GetProperty("ConsoleApplication19.IConnectable.Connection", BindingFlags.NonPublic | BindingFlags.Instance);

Das ganze funktioniert blendend.

Der Name (Type.ToString()) des Interface als generischen Typ wäre z.B. "ConsoleApplication19.IConnectable`1[System.Decimal]" und hier wird es komisch, es funktioniert so nicht. Auch mit FullName nicht!
Stattdessen muss man den Typ komplett im C#-Stil angeben:

var info = t.GetProperty("ConsoleApplication19.IConnectable<System.Decimal>.Connection", BindingFlags.NonPublic | BindingFlags.Instance);

Weiß vielleicht irgendjemand warum das so ist? Ich wüsste auch nicht, wie man den Namen von Type bekommt ohne irgendwie im String rumzupfuschen! Das ganze wundert mich sehr!

PS:
An die anderen, das kommt jetzt vielleicht blöd rüber und man möge es mir verzeihen, aber probiert eure Lösungen doch lieber vorher mal aus.

26.07.2008 - 10:56 Uhr

Sorry, damit bist du fast 5 Jahre hinten dran. Java hat seit 5.0 sogar sehr mächtige Enums! Ich finde die super.

Ups, bei Java verwechsle ich immer was fehlt. 🙂
Aber Sisyphus hat recht, zumindest als ich Swing machen musste, waren da keine Enums. ... War das Swing? Kann mich nicht mehr erinnern, hab ich wohl schon wieder verdrängt. 😉

26.07.2008 - 00:23 Uhr

Ein dynamisches, echtes Enum macht keinen Sinn. Ein Enum ist nichts anderes als eine mit Namen versehene Sammlung von konstanten Integer. Nicht umsonst werden sie in Java bspw. mit public static Feldern erzeugt (zum Glück ist C# da etwas weiter).

Aber was möchtest du laden? Die Namen? Oder die Namen und die Int-Werte? Oder nur die Int-Werte? 🙂

Wenn du nicht komprimieren musst, kannst du doch Tar benutzen. Gibts auch in der SharpZipLib. Vielleicht ist die Performance da besser.

Edit:
Achso, MUSS es denn ein Zip-Archiv sein?

22.07.2008 - 00:46 Uhr

Na ja wenn alls 64 ist, sollte es ja kein Problem sein. Vielleicht hast du aus versehn die falsche dll kopiert. 🙂 Du musst "nur" die richtige Version kopieren, z.B. per Installationsprogramm (find ich richtig nervig).
Schau mal hier: http://sqlite.phxsoftware.com/forums/p/936/4022.aspx#4022

22.07.2008 - 00:33 Uhr

Ist das Vista 64-bit? Es gibt von System.Data.SQLite eine 32-bittige und eine 64-bittige. Entweder kompilierst du dein Programm nur auf 32-bit oder du musst die passende Assembly laden. Das steht auch noch auf meiner Liste. grml Kann mir da jemand einen schnellen Tipp geben?

Hi,
das ganze ist etwas kompliziert zu erklären. Deshalb wird der Post etwas lang und unverständlich. 🙂
Erstmal muss man sich klar machen wie ein Switch funktioniert: es ist eine Sprungtabelle. Das heißt, man springt einfach um eine bestimmte Länge nach vorne (im IL) und ist dann bei der richtigen Instruktion. Natürlich kann man nicht beliebig weit springen, sondern der Compiler benutzt Sprünge ab 0. Angenommen man halt also drei Integer-Cases 0,1,2 ist die Welt schön und gut. Angenommen man hat die Cases 3,4,5 muss der Compiler erst -3 machen. Jetzt gibt es beliebig komplexe Cases die den Compiler verrückt machen, man stelle sich die Cases 32,42,1052 vor. 🙂
Wir haben aber Strings! Also muss der Compiler richtig tricksen. Was er macht ist folgendes: vor dem Switch benutzt er heimlich ein Dictionary<string,int>, packt dort die Cases und die Sprünge (0,1,2,...) rein.

Die IL das Ä sieht dann so aus:

    L_0018: dup 
    L_0019: ldstr "\u00c4" // Das Ä
    L_001e: ldc.i4.0       // Die 0
    L_001f: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)

Die Sprungtabelle ist dann:

    L_0079: switch (L_0098, L_00a0, L_00a8, L_00b0, L_00b8, L_00c0) // Hier steht: springe zu Label L_0098 im Falle 0, L_00a0 im Falle 1, ...
    L_0096: br.s L_00c8 // Hier ist Sprung zu default
    L_0098: ldstr "AE"  // Fall 0 (Ä)
    L_009d: stloc.0
    L_009e: br.s L_00cc // Springe zum Ende des Switches
usw.

Das string-Switch ist also eigentlich eine Lüge (unabhängig von Debug oder Release)! Das können wir auch selbst mit einem Dictionary, und man spart sich das zusätzliche Switch am Ende.

Warum also Switch? Na ja, normalerweise ist ein Switch zugar schneller als entsprechende Ifs! Wenn man also z.B. ein Enum switcht (dessen Werte 0,1,2, ... sind) ist das Switch unschlagbar. Bei Strings ist das eben anders. Wenn man allerdings wenige Cases hat, baut der Compiler das Switch in ein If um. In meinen Fall waren das 6 Cases (default ist auch ein Case) aber ich weiß nicht ob das immer so ist.

switch (input)
{
    case "Ä":
        return "AE";
    case "Ö":
        return "OE";
    case "Ü":
        return "UE";
    case "ß":
        return "SS";
    case "AE":
        return "Ä";
    case "OE":
        return "Ö"; // bis hier ist es großes if, schneller als das unser eigenes Dictionary
    case "UE":      // ab hier ein Dictionary-Switch, langsamer als unser eigenes Dictionary, da wir ein Dict UND Switch benutzen.
        return "Ü";
}

Unterm Strich:
Nimm ein static Dictionary. Das muss nur einmal initialisiert und befüllt werden. Das Switch-Mogel-Dictionary jedes mal. Viele Ifs gingen auch, sind aber hässlich. 🙂

Siehe auch:
http://weblogs.asp.net/justin_rogers/archive/2004/03/25/95806.aspx

21.07.2008 - 11:28 Uhr

Es kommt drauf an was man erreichen will. Geht es nur darum eine String zu haben der keinen Inhalt hat, kann man beides gleichwertig benutzten - dafür gibts dann die IsNullOrEmpty Funktion, muss man aber auch zwischen Leer und uninitialisiert unterscheiden, dann wertet man halt null und String.Empty unterschiedlich.

Roger. Eine Methode gibt null zurück wenn sie sagen möchte "etwas ist nicht zugetroffen oder ich hatte nichts zu tun". String.Empty gibt sie zurück, wenn sie sagen möchte "ich habe etwas getan, aber es gab keine Daten", oder so ähnlich. Für mich macht es keinen Sinn String.Empty generell zurückzugeben, man gibt auch nicht default(Foobar) zurück.

Sowieso erzeuge ich Strings eher per string.Format oder StringBuilder. Klar, wenn es keine Daten gab, sind die eben leer.

PS:
Wie prüft ihr übergebene Parameter? Sagen wir man macht

if (string.IsNullOrEmpty(str))
throw new ArgumentException...;
// oder
throw new ArgumentNullException...;
// oder gleich auf null und string.Empty getrennt prüfen?

😉

Was genau willst du denn vereinfachen? U komplett rauswerfen? Das geht nicht, denn du musst IAction<U> ja irgendwie beschreiben.
Ansonsten könntest du IAction<U> von einem object-basierten IAction ableiten und den Typ anders übergeben. Da käme aber wohl Reflection ins Spiel und das wäre sehr ineffizient. 😉

Verwendetes Datenbanksystem: SQLite + NHibernate 2.0 Beta

Ich hab eine simple Frage. Meine Klassenstruktur ist dead-simple:


abstract class A { }
  class Sub1 : A { }
  class Sub2 : A { }
  class Sub3 : A { }
   class Sub31 : Sub3 { }
   class Sub32 : Sub3 { }
   class Sub33 : Sub3 { }

Das ganze mappe ich natürlich mit NHibernate. 🙂 Jetzt möchte ich die Vererbung auf zwei Arten machen: Sub1-3 als table per subclass, Sub31-2 als table per class hierarchy.

Prinzipell sähe das so aus:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
	<class name="Frage.A, Frage" table="As">
		<id name="ID" column="ID" access="field.lowercase-underscore"><generator class="native" /></id>
		<!-- snip -->
		<joined-subclass name="Frage.Sub1, Frage" table="Sub1s">
			<key column="ID" />
			<property ... />
			<array ... />
		</joined-subclass>

		<joined-subclass name="Frage.Sub2, Frage" table="Sub2s">
			<key column="ID" />
			<property ... />
			<property ... />
		</joined-subclass>

		<joined-subclass name="Frage.Sub3, Frage" table="Sub3s">
			<key column="ID" />
			<discriminator column="Disc" />

			<many-to-one ... />
			<property ... />

			<subclass name="Sub31" discriminator-value="A">
				<property ... />
				<property ... />
			</subclass>

			<subclass name="Sub32" discriminator-value="B">
				<property ... />
				<property ... />
			</subclass>

			<subclass name="Sub33" discriminator-value="C">
			</subclass>
		</joined-subclass>
	</class>
</hibernate-mapping>

Natürlich funktioniert dieser Code nicht. 🙂
Die Hibernate-Reference benutzt hier eine Kombination aus <subclass> und <join>. Das Beispiel funktioniert auch gut (mit NH 2.0), aber wenn ich das übertrage, bekomme ich zwei Probleme:
Erstens ist mein discriminator in einer subclass (kann ich das irgendwie "auslagern"?) und zweitens funktioniert das array nicht in join.

Könnt ihr mir vielleicht helfen? Leider komme ich nicht ganz dahinter. Komplett mit "table per subclass" funktioniert der Code natürlich, aber benötigt zu viele Tabellen (viele davon nur mit einer ID-Spalte).

Gruß
Jabe

09.07.2008 - 22:08 Uhr

Du hast wohl irgendwo ein Dispose() nicht aufgerufen und deshalb das Dateihandle nicht freigegeben. Den Source einfach auf null setzen, zerstört das Handle nicht. Zeig mal bitte den Code der das Bild läd (Converter?).
Im Prinzip müssest du statt xx.Source = null ein ((Image)xx.Source).Dispose() machen.

Ich verstehe zwar leider nur die Hälfte, aber hast du schon mal über eine striktere Struktur nachgedacht? Zum Beispiel MVC (bzw. WPF-Derivate wie MVVC).

Ich kann nur von meinen Erfahrungen mit Db4o in C# berichten:
Db4o ist eine tolle Sache, Objekt rein, Objekt raus, alle glücklich. Dafür funktioniert es super.
Nur leider war das in meinem Fall nicht so einfach. Die Anwendung stand zwischen SQLite und Db4o als Embedded-DB und ich bin zu SQLite gegangen. Ich habe ein schönes Datenmodell, eigentlich perfekt für Db4o (aber auch perfekt für Tabellen), nur ich hatte diese Probleme:*Dateigröße (ein Objekt mit all seinen Kindern: 400 KB, SQLite: 150), schlechter komprimierbar *Defrag-Problem, man muss die File immer mal defragmentieren, da ein Löschvorgang keinen Speicher freigibt. Das Defrag ist allerdings nervig, dann was passiert: Datei schließen, Backup, neue Datei erstellen, öffnen. SQLite brauch nur ein VACUUM-Befehl und gut ist. Dieser ist i.d.R. auch viel schneller und man könnte ihn zugar ans Delete mit dranhängen. *Das Konfigurationsmodell ist schrecklich (weil Java-Port). So setzt man einen Feldindex:
config.ObjectClass(typeof(Foo)).ObjectField("_blah").Indexed(true);

*Geschwindigkeit, selbst mit ActivationDepth und Indices (und DB in-memory zum Test) ist mir eine 30 ms-Query zu langsam. SQLite schafft die gleiche 10-mal so schnell. *Keine "echten" Aggregatfunktion wie Sum, Avg und ich brauche diese in 90% meiner Queries. *SODA, kann wenig aber schnell. Dumm nur, es kann wirklich fast nichts, nicht einmal (ok es ist halt auch nicht immer trivial 😉) case-insensitive Stringvergleiche oder LIKE etc.

*LINQ bzw. NQ, so toll allerdings hat es einige "Quirks": Einfache Queries werden zu SODA übersetzt und besonders bei den ersten Queries nimmt sicht Db4o da gerne mal 1 Sek. Auszeit. Bei komplexen Queries (z.B. mit einem Join 😉) werden viele Objekte aus der DB gezogen und dann wird Linq-to-Objects angewendet.

Du findest das im Build/Erstellen-Menü. 🙂
Im Prinzip löscht das alles "Generierte", also die bin und obj-Ordner. In obj liegen z.B. deine kompilierten XAMLs und ich hatte schon Probleme bei heruntergeladenen Projekten (und bei mir selbst) die obj-Ordner enthielten.

Schwer zu sagen, hast du mal ein "Clean Project/Solution" und dann rebuild probiert? Hin und wieder verheddert sich der XAML-Compiler bisschen.

24.06.2008 - 00:15 Uhr

Dann schau dir mal die Tracing-Messages an. WPF verschluckt zwar Exceptions im Databinding, gibt aber eine Meldung um Output-Fenster von VS (View->Output).

23.06.2008 - 17:17 Uhr

Dein Binding ist korrekt, hast du den DataContext der ComboBox oder eines der Parent-Elemente auf ein Objekt gesetzt? Evtl. müsstest du auch SelectedValuePath rauswerfen, macht hier AFAIK keinen Sinn (WPF sucht dann im DataContext-Objekt das Binding Ansprechpartner und in diesem Objekt wiederrum den SelectedValuePath "Ansprechpartner").

Die Altlasten werden immer nur bereichsweise abgeworfen, siehe WPF. Da gibt es nur sehr wenige Win32-Aufrufe/Wrapper. Hier bietet sich es eben auch an, da der Technologiesprung riesig ist (GDI vs. DirectX).

22.06.2008 - 13:07 Uhr

Ich verstehe nicht ganz wozu. Du redest doch von XBAP (oder?), das als Page in einem Browser läuft. Die Page sollte dann das gesamte Browserfenster einnehmen.
Wozu möchtest du die Größe haben? WPF ist gebaut um 100% Auflösungs-, DPI- und Größenunabhängig zu sein.
Ansonsten könntest du mal probieren die Größe des Root-Elementes (Page) zu holen, per Page.ActualWidth/Height.

13.06.2008 - 17:53 Uhr

Ich würde das Pattern nur dort einsetzen, wo es einen logischen Sinn macht. Siehe StringBuilder, dort kann ich Append().Append().Append() machen. Oder aber, wenn die Implementierung explizit darauf abzielt, wie LINQ.

Im Übrigen bin ich kein Fan von Verkettungen, sie führen zu unübersichtlichen Zeilen und sind unhandlich im Debug und Testing.

PS:
Das mit dem Ändern erinnert mich an Ruby. Dort gibt es String-Methoden wie z.B. upcase(), die eine Kopie des Strings liefert und upcase!(), die das aktuelle Objekt ändert. Schöne Konvention. 🙂

12.06.2008 - 21:16 Uhr

Je nachdem wo du dich bewegst, gibt es für WinForms die BindingList und für WPF die ObservableCollection. Diese Klassen lösen Events aus, wenn man "in" ihnen etwas ändert.
Letztere implementiert übrigens INotifyCollectionChanged (der neue Bruder zu INotifyPropertyChanged); das Teil ist gar nicht mal so trivial zu implementieren, denn bei einer Änderung teilt die Collection mit, welche Items genau geändert wurden (hinzugefügt, gelöscht, etc.).

Wenn du nur ein "da hat sich was geändert" Event brauchst, solltest du dir die Collection selbst (über)schreiben und ein kleines Event machen, ist nicht viel und oft praktischer.

12.06.2008 - 21:04 Uhr

Das genannte Beispiel kann man mit C# 3 auch per Object Initializers erzeugen:

new Rectangle() { Height = 23, Width = 42 };

Hier wird meiner Meinung nach viel klarer, was passiert. Geht natürlich nur bei der Initialisierung.

Außer zum mehr oder weniger bequemen Erstellen des Objektes sehe ich nicht viel Sinn darin.

Rectangle rectangle = new Rectangle().SetHeight(23).SetWidth(42);

rectangle.SetWidth(rectangle.Width + 1).SetHeight(rectangle.Height + 1);

So etwa? Nein danke. Und was ist mit den Properties die ich verwendet habe? GetXxx? Private Setter?
Das Pattern passt überhaupt nicht zu C#, vielleicht zu Java oder C++.

Ich kann nur von meiner VirtualBox-XP-VM berichten.
Vor 3.5 SP1 Beta liefen meine WPF-Anwendungen nicht (mangels DirectX), mit der SP1 Beta läuft auf der VM alles. Im SP1 wurde ja der CPU-Fallback stark ausgeweitet (u.a. für die neuen Effects) und vielleicht hat das auch Auswirkungen auf die Thin Clients.
Die getestete Anwendung benutzt allerdings nur simple Standardelemente, läuft aber so wie auf meinem Vista-Host. OK, 30 mal starten hab ich noch nicht probiert. 🙂

10.06.2008 - 19:59 Uhr

Sorry, aber das ist vollständiger Quatsch, dass Exceptions langsam wären ... das ist so eine der unausrottbaren Urban Legends in der IT.

Exceptions haben keinen negativen Einfluss auf die Performance, und können von daher bedenkenlos genutzt werden. Für eine Erklärung, woher diese Urban Legend kommt, siehe
>

Und? Mal weitergelesen? Der Microbenchmark ist absoluter Quatsch.

Was ich sagen möchte, deine Aussage mit "bedenkenlos benutzten" ist gefährlich. Siehe den Flow-Control-Horror von Rasta. 🙁
Wenn man kann vermeidet man die Exception. Lieber ein TryParse als ein Parse mit Try! Defensive Asserts (if x != null) und Debug.Assert können da helfen.

Almost Rule #1

When deciding if you should throw an exception, pretend that the throw statement makes the computer beep 3 times, and sleep for 2 seconds.

Agreed. Genau so kann man das beschreiben.

02.06.2008 - 19:40 Uhr

Probiers mal mit dem InkCanvas. Kannst dir ja mal aus dem Buch Pro WPF die Beispiele anschauen, Chapter 4.

PS:
Da gibt es auch einen Radiergummi für die Strokes. 😉

Das mit der Performance kenn ich, die ersten Queries sind etwas langsam aber dann wird es wirklich schnell.

.NET nimmt die explizite Equals, ist so eine Guideline von MS. Da entfällt das Boxing zum object und wieder zurück. 🙂
"It is also recommended that in addition to implementing Equals (object), any class also implement Equals (type) for their own type, to enhance performance."

Hi nochmal,
Das mit dem IEqualityComparer war natürlich Quatsch, irgendwie habe ich mich da verhakt. Du musst nur Equals und GetHashCode korrekt überladen (wie bei jeder "Datenklasse" 🙂) und dann funktioniert die normale Distinct-Methode wie gewollt.

Kochbuch-Implementierung wäre:


public override bool Equals(object obj)
{
    if(obj == null)
        return false;

    MyObject my = obj as MyObject;

    if((object)my == null)
        return false; // obj war kein MyObject.

    return VergleichsItem == my.VergleichsItem;
}

// Implementierung mit explizitem Typ aus Geschwindigkeitsgründen
public bool Equals(MyObject my)
{
    if((object)my == null)
        return false; // my war null

    return VergleichsItem == my.VergleichsItem;
}

public override int GetHashCode()
{
    return VergleichsItem.GetHashCode();
}

var query = (from c in datenListe
             select c).Distinct();

// oder kürzer ohne query syntax einfach:
var query = datenListe.Distinct();

Den IEqualityComparer benutzt man nur, wenn man einen speziellen "Vergleicher" brauch, möglichst austauschbar.

PS:
LINQ ist nicht immer schneller, im Gegenteil, man könnte wohl jede Query "von Hand" übertreffen. Trotzdem ist LINQ wesentlich ausdrucksstärker und praktischer. Man erreicht außerdem eine gewissen Abstraktion vom darunterliegenden System, eine Linq2Sql-Query unterscheidet sich nicht stark von einer auf ein IEnumerable.
Eine Erweiterung wird dann (im Herbst AFAIK) PLINQ (Teil der Parallel Extensions) sein, dass eine Query automatisch über mehrer Threads verteilen kann und somit auch moderne CPUs beschäftigen kann. Eine Query mit Joins, GroupBy und Sortierung "von Hand" zu schreiben und über mehrere Threads zu verteilen wäre in dem Fall unglaublich viel komplexer und eine große Qual. 🙂 Hoffen wir, dass PLINQ hält was es verspricht.

30.05.2008 - 15:32 Uhr

Mehrere froms in einer Zeile wie in deinem ersten Beitrag ist nur bei VB möglich. 🙂

Nichtsdestotrotz ist die Distinct-Query mit dem passenden IEqualityComparer schneller als das leicht zweckentfremdete GroupBy. Bei mir etwa 2-3x. 😉