Archiv

Archiv für die Kategorie ‘Microsoft .NET’

Meine Top-3-Entwickler-Tools

Zur Zeit findet auf der MSDN ein Gewinnspiel statt. Darin wird man aufgefordert, einen Beitrag über seine 3 besten Entwicklungstools zu erstellen. Hier kommt meine Liste:

1. JetBrains ReSharper
Der ungeschlagene Favorit ist der ReSharper. Das Tool bietet einmal die Hervorhebung der aktuellen Zeile im Source (klingt trivial, ist mir aber wichtig). Weiterhin prüft und korrigiert es die Groß/Kleinschreibung, was den Source lesbarer macht. Es hat zudem unheimlich mächtige Navigationsfeatures (in Ableitungen springen…) und bietet eine Funktion, um alle Aufrufe einer Funktion/Property/Klasse einfach zu finden.

2. SQL Server Management Studio
Das Management-Studio ist die Software, wenn eine Datenbank für den SQL-Server administriert wird. Was das Tool so wertvoll macht, ist die unheimliche Geschwindkeit, mit der Datenbanken auch übers Web administriert werden können.

3. .NET Reflector
Wenn man unerklärlichen Problemen auf die Spur kommen möchte, oder Warnung nicht versteht, hilft manchmal der Blick in den Reflektor. Damit kann man die wirkliche Umsetzung des Kompilats nachvollziehen und auch ohne Source gelieferte Anwendungen teilweise einfach nachvollziehen.

KategorienMicrosoft .NET, Toolbox Tags:

Registry-Zugriffe bei Windows 64Bit für 32Bit Anwendungen

29. März 2009 Keine Kommentare

Windows 64 Bit setzt sich in Zeiten fallender RAM-Preise immer mehr durch, als Vista64. Bei dem Zugriff auf die Registry stolpert man dabei aber über ungeahnte Probleme.

32Bit Programme legen Ihre Einträge nämlich nicht in der normalen Registry ab, sondern im Unterschlüssel Wow6432Node (wird von Windows umgeleitet):

Auszug aus der Registry unter Vista64

Was bedeutet das für eigene Programme:
Möchte man von einem 64-Bit Programm aus auf Einstellungen eines 32-Bit Programms zugreifen, ist der Unterschlüssel Wow6432Node zu öffnen. Will man von einem 32-Bit Programm Einstellungen eines 64-Bit Programms auslesen, so steht man vor einem Problem. Will man auf die 64-Bit Schlüssel zugreifen, so muss man die Registry mit speziellen Parametern öffnen. Für Delphi findet man eine Lösung in Delphi-PRAXIS. Für .NET ist die Sache erstaunlicherweise komplizierter.
kick it on dotnet-kicks.de

Master Detail mit List<>

Möchte man Listen (System.Collection.Generic.List<>) an Comboboxen mittels einer Master-Detail-Beziehung anbinden, so bietet sich die hier dargestellte Vorgehensweise an.

Code der Listen:

    public class Detail
    {
        public String Caption { get; set; }
        public int Id { get; set; }
 
        public Detail(string caption)
        {
            Caption = caption;
        }
    }
 
    public class DetailList: List<Detail>
    {
        public String DetailListCaption { get; set; }
 
        public DetailList(string masterCaption)
        {
            DetailListCaption = masterCaption;
        }
    }
 
    public class Master: List<DetailList>
    { }

Zur Anwendung wird die Liste bespielhaft befüllt:

    private Master master = new Master();
...
    master.Add(new DetailList("Cap Master 1"));
    master.Add(new DetailList("Cap Master 2"));
 
    master[0].Add(new Detail("Cap Detail 1.1"));
    master[0].Add(new Detail("Cap Detail 1.2"));
    master[1].Add(new Detail("Cap Detail 2.1"));
    master[1].Add(new Detail("Cap Detail 2.2"));

Nun werden noch zwei BindingSource-Komponenten erzeugt und initialisiert:

    masterBindingSource = new BindingSource {DataSource = typeof (Master)};
    comboBox1.DataSource = masterBindingSource;
    comboBox1.DisplayMember = "DetailListCaption";
 
    detailBindingSource = new BindingSource {DataSource = typeof (DetailList)};
    comboBox2.DataSource = detailBindingSource;
    comboBox2.DisplayMember = "Caption";
 
    masterBindingSource.CurrentChanged += masterBindingSource_CurrentChanged;
...
    private void masterBindingSource_CurrentChanged(object sender, EventArgs e)
    {
        detailBindingSource.DataSource = masterBindingSource.Current;
    }

Wichtig ist dann nur noch die Initialisierung der Datasource mit einem konkreten Wert:

    masterBindingSource.DataSource = master;
KategorienMicrosoft .NET Tags: ,

Runden in Microsoft .NET

Es gibt in Microsoft .NET alle gebräuchlichen Möglichkeiten, Zahlen zu runden:

using System;
 
namespace RoundTest
{
    class Program
    {
        static void TestOutput(double value)
        {
            Console.WriteLine();
            Console.Write(value);
            Console.Write("\t Truncate: " + Convert.ToInt32(Math.Truncate(value)));
            Console.Write("\t Ceiling : " + Convert.ToInt32(Math.Ceiling(value)));
            Console.Write("\t RoundAFZ: " + Convert.ToInt32(Math.Round(value, MidpointRounding.AwayFromZero)));
            Console.Write("\t RoundToE: " + Convert.ToInt32(Math.Round(value, MidpointRounding.ToEven)));
        }
 
        static void Main(string[] args)
        {
            TestOutput(10.0);
            // ...
            TestOutput(-10.51);
            Console.ReadLine();
        }
    }
}

Hier ist die Ergebnisausgabe davon zu finden:

10       Truncate: 10    Ceiling : 10    RoundAFZ: 10    RoundToE: 10
10,49    Truncate: 10    Ceiling : 11    RoundAFZ: 10    RoundToE: 10
10,5     Truncate: 10    Ceiling : 11    RoundAFZ: 11    RoundToE: 10
10,51    Truncate: 10    Ceiling : 11    RoundAFZ: 11    RoundToE: 11
 
-10      Truncate: -10   Ceiling : -10   RoundAFZ: -10   RoundToE: -10
-10,49   Truncate: -10   Ceiling : -10   RoundAFZ: -10   RoundToE: -10
-10,5    Truncate: -10   Ceiling : -10   RoundAFZ: -11   RoundToE: -10
-10,51   Truncate: -10   Ceiling : -10   RoundAFZ: -11   RoundToE: -11

kick it on dotnet-kicks.de

KategorienMicrosoft .NET Tags: ,

C# Extensions in Microsoft .NET 2

19. Februar 2009 Keine Kommentare

Möchte man Extensions in C# verwenden, scheint man auf das 3er Net-Framework angewiesen zu sein. Dies ist aber nicht ganz richtig. Legt man folgende Klasse in dem Projekt an:

namespace System.Runtime.CompilerServices
{
    public class ExtensionAttribute : Attribute {}
}

so kann man Extensions, eine 3er Compiler vorrausgesetzt (VS2008), problemlos mit dem .NET Framework 2 als Ziel verwenden.

KategorienMicrosoft .NET Tags: ,

neue C# Anweisung yield return

7. Februar 2009 Keine Kommentare

Bereits mit der Version 2.0 wurde C# um ein mächtiges Feature erweitert: yield return.
Mit C# 3.0 kam dann unter anderem das var dazu. Dazu ein kleines Beispiel:

private static void TestList()
{
    var list = new List<String> { 
        "Dies ist Zeile 1", 
        "HIER KOMMT ZEILE 2", 
        "3 hat nichts", 
        "4 IST NOCH MAL EIN TREFFER" };
    foreach (var item in list)
    {
        Console.WriteLine(item);
    }
 
    Console.WriteLine();
 
    foreach (var item in FilterUpperLines(list))
    {
        Console.WriteLine(item);
    }
}
 
private static IEnumerable<String> FilterUpperLines(List<String> list)
{
    foreach (string elem in list)
    {
        if (elem.ToUpper() == elem)
            yield return elem;
    }
}

var kann bei einer Variablendeklaration anstelle des Typs gesetzt werden, sofern die Definition für den Compiler zwingend ist. Das macht meiner Meinung nach immer dann Sinn, wenn der Typ beispielsweise durch die Initialisierung direkt dahinter nochmals wiederholt wird.

yield kann einem sehr viel Arbeit abnehmen, wenn man Mengen zurückgeben möchte. yield return sammelt quasi die Ergebnismenge ein und gibt sie in Form einer Liste zurück. Das eigentliche Definieren und zurückgeben der Liste übernimmt komplett der Compiler.

Der Clou am var ist übrigens: Diese Funktionen lassen sich auch bei einem Compilat für das Net-Framework 2.0 nutzen! Der Compiler braucht für die Funktionalität keine Features aus dem 3er Framework.

KategorienMicrosoft .NET Tags: ,

Set’s in C#

2. Dezember 2008 Keine Kommentare

Seit dem Wechsel von Delphi auf C# habe die sprechende Art, mit Aufzählungen zu arbeiten, vermisst:

type
  Right = (rRead, rWrite, rDelete);
  Rights = set of Right;
 
var rightSet: Rights;
 
begin
  rightSet := [rRead, rWrite];
  Writeln('Schreibrecht: ' + BoolToStr(rWrite in rightSet));
  rightSet := rightSet - [rWrite];
  Writeln('Schreibrecht: ' + BoolToStr(rWrite in rightSet));
  Readln;
end.

Das gleiche in C# war durchaus effektiv und klar, aber die boolschen Operationen lassen sich oft nicht so intuitiv lesen bzw. umsetzen:

[Flags]
enum Rights
{
    Read = 1,
    Write = 2,
    Delete = 4,
}
 
private static void BoolscherCode()
{
    // üblicher Code
    Rights rights = Rights.Read | Rights.Write;
 
    // prüfen, ob Schreiben enthalten ist:
    Console.WriteLine("Schreibrecht: " + ((rights & Rights.Write) == Rights.Write).ToString());
 
    // Schreibrecht entfernen
    rights &= ~Rights.Write;
 
    // prüfen, ob Schreibrecht enthalten ist:
    Console.WriteLine("Schreibrecht: " + ((rights & Rights.Write) == Rights.Write).ToString());
}

Wintellect bietet mit seiner PowerCollection hier durchaus einen Ausweg:

enum Rights { Read, Write, Delete }
 
private static void ListenCode()
{
    Wintellect.PowerCollections.Set rights = new Wintellect.PowerCollections.Set();
    rights.Add(Rights.Read);
    rights.Add(Rights.Write);
 
    // prüfen, ob Schreiben enthalten ist:
    Console.WriteLine("Schreibrecht: " + (rights.Contains(Rights.Write)).ToString());
 
    // Schreibrecht entfernen
    rights.Remove(Rights.Write);
 
    // prüfen, ob Schreibrecht enthalten ist:
    Console.WriteLine("Schreibrecht: " + (rights.Contains(Rights.Write)).ToString());
}
KategorienMicrosoft .NET Tags: ,

Master-Detail Update Probleme

5. November 2008 Keine Kommentare

Dank Visual Studio und Microsoft .NET in der Version 2 ist es ein leichtes, eine Master-Detail-Beziehung zwischen zwei Tabellen in einem Dataset nachzubilden und auch im Formular zu bearbeiten. Die Erstellung des Datasets übernimmt ein Assistent. Die Controls im Formular werden per Drag&Drop platziert. Dabei wird im Code auch automatisch Code zur Aktualisierung der Datenbank angelegt:

 myMasterTableBindingSource.EndEdit();
 myDetailTableBindingSource.EndEdit();
 tableAdapterManager.UpdateAll(dataSetmyTables);

Soweit, so gut. Leider kann sich für den Anwender dadurch Datenverlust ergeben. Wir ein Detail-Datensatz bearbeitet und dann der Master-Datensatz gewechselt, so bleibt der Detail-Datensatz im Edit-Modus! Mit

 myDetailTableBindingSource.EndEdit();

ist dieser Datensatz nicht mehr zu erreichen und wird auch nicht beim UpdateAll berücksichtigt. Eine Abhilfe schafft hier:

 for (int i = 0; i < dataSetmyTables.myMasterTable.Count; i++)
   { dataSetmyTables.myMasterTable[i].EndEdit(); }
 for (int i = 0; i < dataSetmyTables.myDetailTable.Count; i++) 
   { dataSetmyTables.myDetailTable[i].EndEdit(); }
 tableAdapterManager.UpdateAll(dataSetmyTables);
KategorienDatenbank, Microsoft .NET Tags:

ConnectionString zur Laufzeit setzen

7. Oktober 2008 Keine Kommentare

ConnectionStrings werden von Visual Studio automatisch in die Anwendungseinstellungen übernommen und beinhalten bei lokalen Datenbanken (beispielsweise VistaDB) üblicherweise auch den absoluten Pfad. Für Asp.Net bietet sich wohl eine solche Lösung an:

Data Source=|DataDirectory|\MyDatabase.vdb3

Das funktioniert aber nicht bei WinForm-Anwendungen, weil es das DataDirectory dort nicht gibt. In dem Falle kann man den ConnectionString aber für die Entwicklungsumgebung fix setzen und dann einfach zur Laufzeit korrigieren:

string connString = global::MyLib.Properties.Settings.Default.ConnectionStringMyApp;
string dbName = "MyDatabase.vdb3";
Int32 startPos = connString.IndexOf("Data Source =\"") + 13;
Int32 endPos = connString.IndexOf(dbName + "\"") + dbName.Length;
connString = connString.Substring(0, startPos + 1) +
 "D:\\MyDataDir\\" + dbName + connString.Substring(endPos);
global::MyLib.Properties.Settings.Default["ConnectionStringMyApp"] = connString;

Das funktioniert, wenn man weiß, dass die Properties in den Settings problemlos über Default[] beschrieben werden können.