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: ,

Ghostscript Druckertreiber installieren

15. Januar 2009 Keine Kommentare

Möchte man den Druckertreiber von Ghostscript manuell installieren, so bietet sich folgendes Batch-Skript an:

@echo off
set printerName="WordToPDF Printer"
 
rem Uninstall old Printer
rundll32 printui.dll,PrintUIEntry /n %printerName% /dl
 
set pathDriver="C:\gs\gs8.50\lib\ghostpdf.inf"
 
if not exist %pathDriver% goto Error
 
rem Install printer driver
rundll32 printui.dll,PrintUIEntry /ia /m "Ghostscript PDF" /h "Intel" /f %pathDriver%
 
rem Install printer
rundll32 printui.dll,PrintUIEntry /if /b %printerName% /f %pathDriver% /r file: /m "Ghostscript PDF"
 
:End
echo Printer %printerName% installed
exit /b 0
 
:Error
echo pathDriver %pathDriver% not found
exit /b 1

Eine Quelle für weitere Möglichkeiten der printui.dll sind unter Freigebene Drucker per Script/Kommandozeile verbinden/einrichten zu finden.

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: ,

Alle Datenbanken vom MSSQL sichern

14. November 2008 Keine Kommentare

Immer wieder habe ich den Fall gehabt, eine Sicherung eines Microsoft SQL Servers einzurichten. Dabei ging es meist nur um kleine Datenbanken, manchmal sogar unter der MSDE 2000 oder dem SQL Server 2005 Express. Dazu wurden dann einfach die Dienste gestoppt und die Dateien wegkopiert.

Gerade auf Webserver war die Lösung unbefriedigend. Darum habe ich mir eine neue Lösung gebastelt. Der SQL-Server bietet zwei Kommandozeilenbefehle: bcp und osql.

bcp bietet einem die Möglichkeit, die Ausgabe eines SQL-Befehls in eine Text-Datei zu leiten. Nutzt man nun einen Select, um alle Datenbank zu ermitteln:

SELECT [name] FROM master..sysdatabases

und erweitertert das Ergebnis um den BACKUP DATABASE Befehl, so hat man eine gute Möglichkeit, sich ein Backupskript dynamisch zu erzeugen:

bcp "Select N' use master', N'GO' UNION Select N'BACKUP DATABASE [' + [name] + N'] TO DISK = N''C:\BackupDB\' + [name] + N'.bak'' WITH FORMAT', N'GO' From master..sysdatabases"
 queryout C:\BackupDB\backupskript.sql -S ".\SQLEXPRESS" -T -c -t \r\n

Das sieht ein wenig unübersichtlich aus, da man jeden Befehl in eine neue Zeile bekommen muss (-t \r\n) und zudem nach jedem BACKUP DATABASE Befehl einen GO benötigt. Ist der Befehl durchgelaufen, sollte das Backupskript vorliegen.

Nun ist nur noch dafür zu sorgen, dass das Skript auch aufgerufen wird:

osql -S .\SQLEXPRESS -E -i C:\BackupDB\backupskript.sql

Läuft alles problemlos durch, wird so bei dem Aufruf beider Befehle ein vollständiges Backup alle Datenbanken des angegebenen SQL-Servers gemacht. Getestet habe ich es mit dem Microsoft SQL Server 2005, der MSDE 2000 und dem Microsoft SQL Server 2005 Express Edition.

KategorienDatenbank 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.

EPS-Dateien ohne Adobe nach PDF

6. Oktober 2008 Keine Kommentare

EPS-Dateien sind ohne Frage eine sehr mächtige Möglichkeit, druckfähige Grafiken zu verbreiten. Leider stellt die Weiterverarbeitung oft ein Problem dar, sofern nicht auf sehr kostspielige Programme zurückgegriffen werden kann.

Abhilfe kann man sich hier mit PStill verschaffen. Diese Software ist in der Lage, EPS-Dateien ohne externe Bibliotheken zu verarbeiten. Besonders leistungsstark ist dabei die Möglichkeit, die Konvertierung mittels externer Skripte zu beeinflussen. So wird man in die Lage versetzt, EPS-Dateien beinahe beliebig in PDFs zu plazieren. Alternativ können EPS-Dateien auch direkt in ein PDF umgewandelt werden (welche dann wiederum in andere PDF’s plaziert werden können.

KategorienPDF Tags: , ,