.NET Blog   ·   .NET Casts   ·   .NET GUI Foren   ·   .NET BlogBook   ·   WPF Blogger   ·   visual studio one   ·   ASP.NET professional

  • ACHTUNG - NEUES BLOG

    Ab sofort steht unter http://devtyr.norberteder.com mein neues Blog zur Verfügung. Dieses Blog wird nicht weiter betreut, bleibt aber erhalten. Neue Eintr%auml;ge erfolgen nur mehr im neuen Blog. Kommentare werden ebenfalls nicht mehr behandelt. Wer weiterhin meinen Einträgen und Aktivitäten folgen möchte, möge bitte RSS-Feeds, Verlinkungen etc. an die neue Location anpassen.
Download .NET Essentials Installer
Trickkiste

Extern aliases: Gleichen Namespace aus unterschiedlichen Assemblies nutzen

16.01.07 - .NET, Grundlagen, Base Framework
Beitrag von Norbert Eder
 Das .NET Framework < 2.0 unterstützte lediglich eine einzelne Namespace-Hierarchie. In diese wurden die Typen der referenzierten Assemblies geladen und konnten anschließend verwendet werden. Dies ist allerdings eher unschön, wenn beispielsweise die gleiche Assembliy, allerdings in unterschiedlichen Versionen, verwendet werden muss oder eine benötigte Assembly zufällig denselben Namespace benutzt wie eine ganz andere. Mit extern aliases ist dieses Problem zu lösen.

Gegeben sind zwei Assemblies.

Assembly a1.dll
namespace N
{
    public class A {}
    public class B {}
}

Assembly a2.dll
namespace N
{
    public class B {}
    public class C {}
}

Bei nachfolgendem Programm würde es nun zu einem entsprechenden Fehler gelangen:
class Test
{
    N.A a; // Ok
    N.B b; // Fehler
    N.C c; // Ok
}

Kompilieren wir nun den Code mit folgender Anweisung:
csc /r:a1.dll /r:a2.dll test.cs

Die Typen aus den Assemblies a1.dll und a2.dll werden in der Global Namespace Hierarchy abgelegt, wodurch ein Fehler entsteht: Der Typ N.B existiert in beiden Assemblies. An dieser Stelle kommen die extern aliases zum Einsatz:
extern alias X;
extern alias Y;

class Test
{
    X::N.A a;
    X::N.B b1;
    Y::N.B b2;
    Y::N.C c;
}

Es werden die beiden Aliase X und Y deklariert, aber die Defintionen der Aliase sind extern abgelegt. Der Kompilierungsaufruf muss entsprechend abgeändert werden und sieht so aus:
csc /r:X=a1.dll /r:Y=a2.dll test.cs

Unter Verwendung von Visual Studio können die Aliase in der Eigenschaft Aliases der jeweiligen Referenz angegeben werden.

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Mit IComparable nach mehreren Eigenschaften sortieren

16.01.07 - .NET, Grundlagen, Base Framework
Beitrag von Norbert Eder
 Nehmen wir als Beispiel eine Highscore-Liste. Hierfür müssen zwei Werte sortiert werden:

- der erreichte Score (absteigend)
- der Name des Spielers (aufsteigend)

Mit Hilfe der Schnittstelle IComparable kann dies einfach erledigt werden. Hierfür benötigen wir die Datenklasse Highscore, welche besagtes Interface implementiert:
using System;
using System.Collections.Generic;
using System.Text;

namespace HighscoreTest
{
    public class Highscore : IComparable
    {
        private string _name = String.Empty;
        private int _score = 0;

        public string Name
        {
            get { return this._name; }
            set { this._name = value; }
        }

        public int Score
        {
            get { return this._score; }
            set { this._score = value; }
        }

        public Highscore(string name, int score)
        {
            this._name = name;
            this._score = score;
        }

        public override string ToString()
        {
            return this._name.PadRight(20, ' ') + this._score;
        }

        #region IComparable Members

        public int CompareTo(Highscore other)
        {
            if (this._score.CompareTo(other._score) == 0)
                return this._name.CompareTo(other._name);
            else
                return this._score.CompareTo(other._score) * (-1);
       }

        #endregion
    }
}

Wie in der Methode CompareTo zu sehen ist, ist eine signifikante Eigenschaft auszuwählen. Diese ist die Eigenschaft, die vorrangig sortiert werden soll. In unserem Fall der Score. Sind die zu vergleichenden Werte identisch, wird der Name sortiert.

Getestet werden kann dies mit Hilfe der folgenden Zeilen:
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Diagnostics;

namespace HighscoreTest
{
    class Program
    {
        static void Main(string[] args)
        {
            List highscoreList = new List();
            highscoreList.Add(new Highscore("Norbert2", 17));
            highscoreList.Add(new Highscore("Norbert1", 17));
            highscoreList.Add(new Highscore("Norbert3", 3));
            highscoreList.Add(new Highscore("Karl", 3));

            highscoreList.Sort();

            Debug.WriteLine("Highscore");
            Debug.WriteLine("--------------------");
            foreach(Highscore hscore in highscoreList)
                Debug.WriteLine(hscore);

        }
    }
}

Wie zu sehen ist, gar nicht so schwierig und keinesfalls aufwändig.

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Es muss nicht immer AJAX sein ...

14.01.07 - Entwicklung, Diskussionen, .NET, Grundlagen, ASP.NET
Beitrag von Norbert Eder
 Wer AJAX nicht einsetzt ist doof. Hört man zumindest Vögel zwitschern. Aber es gibt auch andere Möglichkeiten.

Für viele Dinge ist es zudem auch gar nicht nötig, AJAX einzusetzen, da simple JavaScripts durchaus ausreichen. So ist vor dem Einsatz von AJAX darüber nachzudenken, welcher Zweck erfüllt werden soll und ob es nicht andere - einfachere - Lösungen gibt.

Wer zudem fit in C++ ist, hat die Möglichkeit auf binary HTML Components [1] zu setzen. Zugegeben, schon recht alt, aber funktioniert sehr flott - und ein riesiges Framework ist auch nicht notwendig.

Implementing Binary DHTML Behaviours

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Eigenschaften und Zugriffsmodifizierer

12.01.07 - .NET, Grundlagen, Base Framework
Beitrag von Norbert Eder
 Man nehme folgendes Interface:
Interface
public interface IPerson
{
    string Firstname { get; set; }
    string Lastname { get; set; }
    DateTime Birthday { get; }
}

Dieses Interface beschreibt, dass die Eigenschaft Birthday nur gelesen werden darf, ein Setzen ist nicht möglich. Um dies aber in der Assembly zu erlauben, in der sichi auch das Interface befindet kann folgendes definiert werden:
public class Person : IPerson
{
    private string _firstname = null;
    private string _lastname = null;
    private DateTime _birthday;

    public string Firstname
    {
        get { return this._firstname; }
        set { this._firstname = value; }
    }

    public string Lastname
    {
        get { return this._lastname; }
        set { this._lastname = value; }
    }

    public DateTime Birthday
    {
        get { return this._birthday; }
        internal set { this._birthday = value; }
    }
}

Der internal Zugriffsmodifizierer sorgt dafür, dass der Setter in derselben Assembly aufgerufen werden kann. Dies ist in vielen Fällen sehr hilfreich.

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Generische Methoden und deren Aufruf

12.01.07 - .NET, Grundlagen
Beitrag von Norbert Eder
 Einfach auf der Zunge zergehen lassen oder in eine Consolen-Anwendung kopieren und austesten.
class Program
{
    static void Function<T>(int x, T y)
    {
        Console.WriteLine("Function 1");
    }

    static void Function<T>(T x, long y)
    {
        Console.WriteLine("Function 2");
    }

    static void Main()
    {
        Function<int>(5, 324);
        Function<byte>(5, 324);
        Function(5, 324);
        Console.WriteLine();
    }
}

  3 Kommentare - 961 mal angesehen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Variable Anzahl an Methoden-Parametern

08.01.07 - .NET, Grundlagen
Beitrag von Norbert Eder
 Wer eine variable Anzahl an Parametern in einer Methode benötigt, der hat vermutlich bereits das Schlüsselwort params entdeckt. Wer nicht, dem sei es hiermit erklärt:

Das Schlüsselwort params ermöglicht es, einer Methode eine beliebige Anzahl an Parametern zu übergeben. Im Gegensatz zu einem Array können die einzelnen Werte mit Hilfe eines Komas getrennt werden, so wie es beispielsweise auch bei einem String.Format funktioniert.

Im folgenden Beispiel wird eine generische Liste durch eine Methode AddMultipleStringsToList erweitert, welche diese Funktionalität bietet:

public class MultipleStringList : List<string>
{
public void AddMultipleStringsToList(params string[] values)
{
foreach (string s in values)
this.Add(s);
}
}

Zusätzlich zu den Methoden Add und AddRange ist nun die neue Methode AddMultipleStringsToList verfügbar, die folgendermaßen verwendet werden kann:

MultipleStringList mStringList = new MultipleStringList();
mStringList.AddMultipleStringsToList("test1", "test2", "test3", "test4");

foreach (string s in mStringList)
Console.WriteLine(s);


  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Schlüsselwort sealed

06.01.07 - .NET, Grundlagen
Beitrag von Norbert Eder
 Von einer Klasse die mit dem sealed-Schlüsselwort gekennzeichnet ist, kann nicht vererbt werden (sealed = versiegelt). Dies bedeutet, dass Erweiterungen nicht gewünscht sind bzw. eine weiterer Abstraktion ohnehin sinnlos wäre. Aufrufe an versiegelte Klassenmember können durch Laufzeitoptimierungen beschleunigt werden.

Beispiel


public sealed class TestClass
{
private int _a = 0;
private int _b = 0;

public int A
{
get { return this._a; }
set { this._a = value; }
}

public int B
{
get { return this._b; }
set { this._b = value; }
}
}


Ergänzungen

Strukturen (structs) sind per Definiton sealed und können daher nicht vererbt werden.
Eine Verwendung von sealed gemeinsam mit abstract ist nicht erlaubt, da man bei einer abstrakten Klasse davon ausgehen kann, dass die konkrete Implementierung nicht existiert.

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Paper zur Common Language Infrastructure (CLI)

01.01.07 - .NET, Grundlagen
Beitrag von Norbert Eder
 Die CLI-Spezifikation gibt es ja schon einige Jahre (klarerweise), doch haben sich die meisten .NET Entwickler die Paper zur CLI gespart. Hier einfach die Links zu den entsprechenden Dokumenten. Ein Durchlesen erhöht auf jeden Fall das Verständnis für .NET und die Arbeitsweise im Hintergrund.

CLI Partition I - Concepts and Architecture

CLI Partition II - Metadata Definition and Semantics

CLI Partition III - Common Intermediate Language (CIL) Instruction Set

CLI Partition IV - Profiles and Libraries

CLI Partition V - Annexes

Damit sollte die Freizeit für den Jänner 2007 erledigt sein - wer's noch nicht gelesen hat ;-)

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Design und Implementierung der .NET Generics

22.12.06 - .NET, Grundlagen
Beitrag von Norbert Eder
 Wer sich ausführlicher mit der Implementierung der Generics (Parametric Polymorphism) in der CLR auseinander setzen möchte, dem sei nachfolgender Artikel für den Start (quasi als Entrypoint) ans Herz gelegt:

Design and Implementation of Generics for the
.NET Common Language Runtime
(PDF, 134 KB)

Weiters empfiehlt sich der MSDN Artikel
Introducing Generics in the CLR.

Und zum Schluss noch ein Link, der in die Generics-Programmierung noch ein wenig Licht bringt: Generics (C# Programming Guide).

Wer jetzt noch immer nicht genug von Generics hat, dem sei noch das Projekt Generics.NET auf CodePlex empfohlen.

PS: Sollte jemand noch Links allgemeinen Generics-Themen (unterschiedliche Ansätze, Implementierungen in unterschiedlichen Programmiersprachen, etc.) in seinen Bookmarks gesetzt haben, dann bitte nur her damit ;-)

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL


Einführung Garbage Collector

11.01.06 - .NET, Grundlagen
Beitrag von Norbert Eder
 Garbage Collection unter C# sieht im Prinzip folgendermaßen aus:

Der GC wird meist dann angetriggert, wenn der Heap-Speicher aufgebraucht sprich voll ist, manuell gestartet wird, oder wenn ein anderes Programm mehr Speicher benötigt, als aktuell noch frei ist.

Der GC iteriert durch den Heap und markiert zuerst jedes Objekt als Garbage, also setzt es auf "zu verwerfen". Danach wird nochmals jedes Objekt rekursiv überprüft, ob Referenzen darauf zeigen - es also noch benutzt wird. Jedes Mal, wenn ein Objekt vom Garbage Collector besucht wird, wird es als erreichbar markiert. Nach diesem Durchlauf steht nun fest, welche Objekte erreichbar sind und welche nicht. Zyklische Referenzen (also Objekt A referenziert Objekt B, welches Objekt C referenziert, welches wiederum Objekt A referenziert) werden ebenfalls entsprechend behandelt.

Im nächsten Schritt wird der Managed Heap durchlaufen und dieser kompaktiert. Das bedeutet, dass Objekte, die verworfen werden können durch Objekte, die im Heap weiter oben gelagert sind überschrieben werden. Dadurch verkleinert sich der Heap und benötigte Objekte wandern weiter nach unten. Es entstehen also keine "Löcher" Heap (Fragmentierung). Dadurch müssen natürlich auch alle Referenzen vom GC geändert werden. Dies ist natürlich ein aufwändiges Unterfangen und aus diesem Grund sollte der GC manuell nur aufgerufen werden, wenn dies unbedingt notwendig ist.

Wann werden Objekte nicht mehr benötigt? Beispielsweise werden in einer Methode unterschiedliche Objekte instanziert. Wurde diese Methode durchlaufen, werden diese Objekte natürlich nicht mehr benötigt und werden beim nächsten Durchlauf des GC entsprechend behandelt. Sie müssen also nicht explizit auf null gestellt werden. Anders verhält es sich bei Objekten, die "expensive resources" (Dateien, Socket-Verbindungen, Ports, Daten Strukturen etc.) enthalten. Hier bietet .NET die object finalization an. Werden also Verbindungen etc. benutzt sollte eine Methode Finalize() vorhanden sein. Diese wird bei der Freigabe des Objektes aufgerufen und somit können verwendete Resourcen auch entsprechend behandelt bzw. tatsächlich freigegeben werden. Hier ist zu beachten, dass die Finalize()-Methode der Basisklasse auch aufgerufen wird. Weiters immer einen try-catch-Block darum ziehen.

Eine weitere Möglichkeit besteht durch das Dispose()-Pattern. Hier ist eine Methode Dispose() zu implementieren. Durch den Aufruf von Dispose werden alle teuren Resourcen entsprechend freigegeben - wie auch in der Finalize()-Methode muss hier der Code für die Freigabe der Ressourcen manuell eingetragen werden. Die Ressourcen werden durch diesen Aufruf sofort freigegeben - ausser man wartet auf den Garbage Collector.

Die schönere Variante besteht darin, das IDisposable()-Interface zu implementieren. Dadurch wird die Methode Dispose() vorgeschrieben und muss entsprechend implementiert werden.

Natürlich gäbe es an dieser Stelle noch mehr zu sagen, aber das sollte als kurzer Überblick durchaus reichen.

  Kommentar hinzufügen   |  0 Trackbacks   |  Permalink  |  Trackback-URL



Zurück Weiter