Korrekturlesen

Fazsinierend! Brathering! Wobei dieser Autopilot auch in die andere Richtung funktioniert. Vor allem in Bezug auf selbst geschriebene Texte, verfällt das Gehirn gern in einen Energiesparmodus.

“[…] die Fähigkeiten des menschlichen Gehirns, sich oft Wiederholtes gut einprägen zu können. […] Deshalb sind Tippfehler übrigens auch kein Zeichen für mangelnde Rechtschreibkenntnisse: je geübter ein Schreiber im Lesen ist, desto häufiger wird er eigene Tippfehler übersehen. […]” www.fehler-haft.de

Ich bin davon leider auch betroffen und präge mir mein Geschriebenes schnell ein. Vor allem da ich meine Sätze während des Schreibens noch öfter anpasse. Dies ist natürlich keine Entschuldigung und ich sollte mich wohl besser konzentrieren. Zur Hilfe gibt es diverse Tipps und Tricks, Nummer 8 ist wohl der Beste. Aber im Ernst finde ich Nummer 4 und 7 am Interessantesten.

PS: Brathering

ProcessorAffinity

Rechenintensive Aufgaben können hin und wieder viel Last auf einem System verursachen. Eine Anwendung, an der ich mitwirke, arbeitet beispielsweise mit vielen Threads und wird sogar mehrfach gestartet. Vor allem dieses mehrfache Ausführen des Prozesses führt schnell zur Überlastung des Servers.

Eine 100% Auslastung ist aber nicht gewünscht. Der Server soll weiterhin Kapazitäten für sich, betriebliche Anforderungen und andere Anwendungen zur Verfügung haben.

Die Idee einer zentralen Steuerung und dynamischen Anpassung der Anzahl der Threads über mehre Prozesse hinweg verwarf ich schnell. Mir wurde auch öfters der Spruch “Die Verwaltung von Threads kann das Betriebssystem viel besser.” um die Ohren gehauen. Ja aber wie sorge ich dafür dass es auf meinem Server nicht so aussieht:

100% Last

Eigentlich ganz einfach so:

taskmgr 

Indem man beispielsweise die Häkchen für CPU0 und CPU1 entfernt:

75% Last

Nun werden 6 von 8 (75%) meiner CPUs unter Last gesetzt. Also mein System reagiert noch und die Anwendung rechnet auch. Nun das Ganze im Code:

   1: using System.Diagnostics;

   2: ...

   3:  

   4: Process process = Process.GetCurrentProcess();

   5: //CPU 7 6 5 4 3 2 1 0

   6: //Use 1 1 1 1 1 1 0 0

   7: // = 252

   8: process.ProcessorAffinity = (IntPtr)252;

Im Test hatte ich einen Rechner mit 24 Kernen und habe dort mal einen Durchlauf auf 22 Kernen und  mit 20 Threads gemacht, sie benötigte 3h 30min. Bei zwei parallelen laufenden Anwendungen ergab die Messung 7h 5min ± 2 min.

Also das Betriebssystem macht seine Aufgabe sehr gut:

  • Nur die zugewiesenen CPUs werden “belastet”.
  • Ein Prozess nutzt die maximal erlaubten Ressourcen (CPUs).
  • Kommen weitere Prozesse dazu werden diese Ressourcen untereinander aufgeteilt.
  • Beendet sich ein Prozess (Rechnung fertig) werden die nun freien Ressourcen automatisch von den verbleibenden Prozessen genutzt.
  • Über die Priorität des Prozesses können wichtige Rechnungen, auf Kosten der anderen, beschleunigt werden.

Alles mit nur einer Zeile Code ….

Powershell: Spaß mit Arrays

Beim Finden von Dateien mit Get-ChildItem im Verzeichnis hatte ich viel Spaß. Solange mehre Dateien vorhanden waren, hat alles wunderbar funktioniert, sobald aber nur eine Einzelne vorlag nicht. Warum?

In folgendem Code suche ich alle txt-Dateien unterhalb meines Ordners .Data. Für jede Datei soll eine Zeile ausgegeben werden. Eigentlich einfach, aber das Powershell Script funktioniert nicht immer:

$items = Get-ChildItem -Path .Data -Filter *.txt
for($i = 0; $i -le $items.Length 1; $i++){
     Write-Host("Item $($i) :$($items[$i])") }

 

Bei zwei gefunden Dateien sieht der Output so aus:

Item 0 :File1.txt
Item 1 :File2.txt
 

Liegt nur eine Datei vor, kommt es nicht zum Aufruf von Write-Host. Warum? Geben wir mal $items.Count, $items.Length und $items.GetType().FullName aus:

Count   :2
Length  :2
Type    :System.Object[]
 

Nun anstatt mit zwei mit nur einer Datei:

Count   :1
Length  :0
Type    :System.IO.FileInfo
 

Wait, What? Length ist 0, weil das untypisierte Ergebnis Get-ChildItem mal ein Array und mal ein FileInfo ist. Wie immer gibt es mehre Lösungen:

  • Immer per Count zugreifen
  • Immer durch @() ein Array erzwingen
  • Sonderfall im Code
  • ….

Die 1. Lösung ist selbsterklärend, aber hier mal die 2.:

$items = @(Get-ChildItem -Path .Data -Filter *.txt)
for($i = 0; $i -le $items.Length 1; $i++){
     Write-Host("Item $($i) :$($items[$i])") }

 

Nun erhält man auch bei einer Datei:

Count   :1
Length  :1
Type    :System.Object[]
 

Vieles ist schnell und einfach in untypisierten Skriptsprachen machbar. Ohne Compiler aber erst zur Laufzeit prüfbar und damit nicht so einfach zu finden und zu testen.

Task Parallel Library (TPL)

Wenn man

        • das Einfrieren der Oberfläche verhindern
        • rechenintensive Aufgaben auf mehre CPUs verteilen
        • im Hintergrund auf Events warten

will, kommt man um parallele Verarbeitung nicht herum.

Seit jeher kann man für diese Aufgaben Threads oder besser einen Threadpool verwenden. Nachteilig muss man sich, vor allem bei Threads, um deren Verwaltung kümmern. Mit .NET 4.5 gewann durch async and await die TPL (Task Parallel Library) große Beachtung und Bedeutung. Mit Task wurde die Basis aber bereits in .NET 4.0 gelegt.
Bei beiden Konzepten werden zwar Aufgaben parallel abgearbeitet, aber Tasks bieten eine höheren Abstraktionslevel und mehr Kontrolle.

  • Cancellation von Tasks
  • Load Balancing von Tasks durch Threadunabhängigkeit
  • bessere Performance/Skalierbarkeit von Tasks durch Threadunabhängigkeit

Die Klasse Parallel perfektioniert das Konzept der Tasks noch, indem sie intern die Aufgaben portioniert bzw. partitioniert. Mit nur einem Aufruf nutzt man die Ressourcen ohne viel Aufwand bestens aus.

Parallel.For(

    0, 

    3, 

    i => Console.WriteLine(i));

Parallel.Invoke(

    () => Console.WriteLine(1),

    () => Console.WriteLine(2),

    () => Console.WriteLine(3));

Parallel.ForEach(

    new int[] { 1, 2, 3 },

    i => Console.WriteLine(i));

Specflow

Mit “Specflow – Binding business requirements to .NET code” begrüßte mich eine Artikelüberschrift in einer Entwicklerzeitschrift. Hierbei kamen für mich mehre interessante Aspekte, wie die Abbildung von fachlichen Anforderungen, automatisierbare Testfälle und Codegeneratoren zusammen. Laut eigener Aussage wurde das zugrundeliegende Framework auf über 40 Programmiersprachen implementiert. Meine Neugier war geweckt.

Specflow ist eine von vielen Umsetzungen von Behaviour Driven Development (BDD). Hierbei sollen die Stakeholder, bzw. die Product Owner mehr in die Implementierung einbezogen werden, um das Produkt, die Software, mehr auf den fachlichen Nutzen zu fokussieren. Bei BDD handelt es sich um eine Erweiterung von Test Driven Development (TDD). Bevor also ein Feature umgesetzt wird, werden Testfälle geschrieben. Bei BDD von der Fachseite. Sie definiert ihre Fachanforderungen in einer allgegenwärtige Sprache, auch Ubiquitous Language oder Domain Specific Language (DSL) genannt. Wie im Bild dargestellt wird dann aus dieser Definition über ein Framework Code generiert.
Specflow ist eines von vielen Cucumber Frameworks, die auf der Sprache Gherkin aufsetzen. Ursprünglich hat alles mit Ruby angefangen, heute werden neben C# auch viele andere Sprachen bedient.

DSL

Gherkin und Cucumber beziehen sich auf das Wort “Gurke”, Gurkengrün oder passend übersetzt Grasgrün und soll auf den gewünschten finalen grünen Status der Testfälle anspielen. Die fachlichen Anforderungen werden als Features in Szenarien zerlegt. Jedes Szenario führt zu einem Akzeptanztest. Diese können in Testrunnern, wie MSTest oder NUnit ausgeführt werden.

Cucumber Szenario

Specflow generiert hieraus eine C# Testklasse, die man noch mit Leben füllen muss. Es erstellt lediglich die Klasse samt Methoden und führt den Aufruf zur Laufzeit durch.

Klassengerüst

Das fast komplette “Getting Started” Beispiel findet sich auf Specflow.org. Lediglich die Anpassungen der App.config fehlen, hier muss angegeben werden für welche Testrunner man die Tests erzeugt haben möchte:

   1: <unitTestProvider name="MSTest" />

   2: oder

   3: <unitTestProvider name="NUnit" />

   4: oder

   5: ...

Als Entwickler kann ich nur implementieren, was ich verstanden habe. Für mich ist dies immer der Haken an TDD, denn auch meine Tests spiegeln nur mein Wissen wieder. Auf der einen Seite begegnen mir heute riesige Fachdokumente und auf der anderen “War doch klar” Aussagen. Nichts ersetzt die direkte Kommunikation, denn auch Anforderungen präzisieren sich meist erst beim Reden und drüber nachdenken. Aber ich denke mit BDD und Cucumber gibt es eine gute Möglichkeit fachliche Anforderungen festzuhalten und besser testbar zu machen.

Die Erfahrungen in solch einem Umfeld zu arbeiten würde ich schon gerne einmal machen.

Ping WCF/Web Service

Wie stellt man im Code fest ob ein WCF/Web Service überhaupt erreichbar ist?

Untitled

Wenn man die Möglichkeit hat, die Hostseite um eine Methode void Ping() oder dynamisch zu erweitern, ist dies relativ einfach. Doch meist hat man über den Host keine Kontrolle. Im Folgenden möchte ich für die Protokolle nettcp und http/https aufzeigen, wie man herausfindet ob der entsprechende Service erreichbar ist, ohne eine Methode (OperationContract) aufzurufen. Leider ist dies immer protokollabhängig

ping nettcp

Beim Protokoll nettcp ist dies relativ einfach, denn die Verbindung wird wirklich beim Open() aufgebaut und geprüft. Entweder nutzt man dafür den generierten Proxy (ClientBase<T>) oder die ChannelFactory<T> direkt, denn beide sind von ICommunicationObject vererbt.

private bool Open(ICommunicationObject  channel)

{

    try

    {

        // Verbindung aufbauen

        channel.Open();

        channel.Close();

        

        return true;

    }

    catch(Exception ex)

    {

        //log ex

        return false;

    }

}

ping http/https

Open() reicht hier nicht aus, denn die Verbindung wird nur kurz für den Request und Response geöffnet. Somit muss man den Server wirklich anfragen. Am besten wäre dies wohl über die Erweiterung des ServiceContracts (siehe oben: void Ping() oder dynamisch zu realisieren. Ohne Einfluss auf die Implementierung des Hostes ist man jedoch auf andere Mittel und Wege angewiesen. Bei HTTP bieten sich dafür die HTTP-Methods an. Wobei nachteilig nicht jeder Service diesen Standard vollumfänglich bereitstellt. Aus diesem Grund durchlaufe ich mehre Request, beginnend mit den gängigsten HTTP-Methods. Sobald einer erfolgreich war, ist der Service erreichbar. Durch ein detaillierteres Fehlerhandling wäre es ebenfalls denkbar den Status des Services abzuleiten. Beispielsweise würde ein “Access Denied” bedeuten, dass der Service online ist.

using System.Net;

 

private bool SendHttpWebRequest(Uri uri)

{

    if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)

        return false;

 

    foreach (string method in new string[] { "GET", "OPTIONS", "HEAD", "TRACE", "CONNECT" })

    {

        try

        {

            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.CreateDefault(uri);

 

            httpRequest.UseDefaultCredentials = true;

            httpRequest.Method = method;

 

            using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse())

            {

                if (httpResponse.StatusCode == HttpStatusCode.OK)

                    return true;

            }

        }

        catch

        {

            //alles wegfangen

        }

    }

 

    return false;

}

yield return

Dieses Sprachfeature gibt es zwar schon etwas länger, jedoch hat es bei mir etwas gedauert damit warm zu werden. Auch die Beispiele, die ich bisher gesehen habe, waren mir nicht immer einleuchtend. Deshalb habe ich es mal für mich verständlich zerlegt.

Starten möchte ich mit for-Schleifen, hierbei werden x und y durch die Methode Add einfach aufsummiert. Die Add Methode simuliert dabei eine langlaufende Methode, um später die Performance der jeweiligen Implementierung besser aufzeigen zu können.

   1: private static IEnumerable<int> CallSimpleLoop()

   2: {

   3:     IList<int> items = new List<int>(); 

   4:     for (int x = 0; x < 3; x++)

   5:     {

   6:         for (int y = 0; y < 3; y++)

   7:         {

   8:             items.Add(Add(x, y));

   9:         }

  10:     } 

  11:     return items;

  12: }

  13:  

  14: private static int Add(int x, int y)

  15: {

  16:     Thread.Sleep(100); //simulate long running worker

  17:     return x + y;

  18: }

Im Beispiel werden dann immer die ersten beiden Items übersprungen und dann die nächsten beiden herausgesucht.

   1: CallSimpleLoop().Skip(2).Take(2).ToList()

Als yield könnte das ganze so aussehen. Obwohl es sich beim Ergebnis wieder um ein IEnumerable<int> handelt, kann das Verhalten beider Lösungen nicht unterschiedlicher sein. Während beim SimpleLoop oben die Add Methode immer gleich ausgeführt wird und nur das Ergebnis in der Liste abgelegt wird, wird hier der Aufruf selbst übernommen. Er wird nur beim Auslesen ausgeführt.

   1: private static IEnumerable<int> CallYieldLoop()

   2: {

   3:     for (int x = 0; x < 3; x++)

   4:     {

   5:         for (int y = 0; y < 3; y++)

   6:         {

   7:             yield return Add(x, y);

   8:         }

   9:     }

  10: }

Heißt hier werden nur die ersten 4 Adds ausgeführt. 2-mal für Skip und 2-mal für Take.

   1: CallYieldLoop().Skip(2).Take(2).ToList()

Aber was heißt er wird nur beim Zugriff ausgeführt? Was versteckt sich hinter jedem Item des yield Iterators?

Ich werde im Folgenden nur das Innere des “on demand” Verhalten von yield betrachten. Den äußeren Teil, wie also der Enumerator durchlaufen und das Current (Item) ausgeführt wird lasse ich außen vor. Somit kann man sich jedes Item sehr vereinfacht als Functionpointer (Delegate) vorstellen.

   1: private static IEnumerable<Func<int>> CallSimpleFuncLoop()

   2: {

   3:     IList<Func<int>> items = new List<Func<int>>();

   4:     for (int x = 0; x < 3; x++)

   5:     {

   6:         for (int y = 0; y < 3; y++)

   7:         {

   8:             items.Add(() => Add(x, y));

   9:         }

  10:     }

  11:     return items;

  12: }

Hier iteriert man jedoch durch die Delegates und muss am Ende den Wert über den Aufruf im Select erst noch berechnen lassen.

   1: CallSimpleFuncLoop().Skip(2).Take(2).Select(i => i()).ToList()

Während jedoch beim YieldLoop neben den Takes auch die Skips ausgeführt werden, werden beim FuncLoop nur die Selects ausgeführt. Dies schlägt sich in der Performance nieder. Am längsten benötigt der SimpleLoop, hier werden auch alle Add Aufrufe ausgeführt, dafür liegen dann aber auch alle Ergebnisse vor. Da der YieldLoop die Add Methode 4-mal aufruft benötigt er ca. doppelt so viel Zeit wie der FuncLoop. Er führt die Add Methode nur 2-mal aus!

SimpleLoop start

925,4136

SimpleLoop end

CallYieldLoop start

405,3873

CallYieldLoop end

CallSimpleFuncLoop start

206,5743

CallSimpleFuncLoop end

Wie bei allen LINQ Features sollte man auf Performance achten, meist liegen die Ergebnisse nicht vor sondern werden erst für den einzelne (jeden!!!) Zugriff aufgebaut. Genau dafür ist LINQ konzipiert!

Hier eine kleine Erweiterung, die diesen Mechanismus aushebelt. Dabei wird um das Delegate ein Wrapper gestrickt, der sich merkt ob das Delegate schon ausgeführt wurde.

   1: public class Wrapper

   2: {

   3:     private object m_lockObject = new object();

   4:     private bool m_loaded = false;

   5:     private int m_data;

   6:  

   7:     private Func<int> m_getData;

   8:  

   9:     public Wrapper(Func<int> getData)

  10:     {

  11:         this.m_getData = getData;

  12:     }

  13:  

  14:     public int Data

  15:     {

  16:         get

  17:         {

  18:             lock (m_lockObject)

  19:             {

  20:                 if(!m_loaded)

  21:                 {

  22:                     m_data = m_getData();

  23:                     m_loaded = true;

  24:                 }

  25:                 return m_data;

  26:             }

  27:         }

  28:     }        

  29: }

  30:  

  31: private static IEnumerable<Wrapper> CallWrapperFuncLoop()

  32: {

  33:     IList<Wrapper> items = new List<Wrapper>();

  34:  

  35:     for (int x = 0; x < 3; x++)

  36:     {

  37:         for (int y = 0; y < 3; y++)

  38:         {

  39:             items.Add(new Wrapper(() => Add(x, y)));

  40:         }

  41:     }

  42:  

  43:     return items;

  44: }

Auch hier wird das Delegate erst im Select ausgeführt, also 2-mal.

   1: CallWrapperFuncLoop().Skip(2).Take(2).Select(i => i.Data).ToList()

Der Unterschied zwischen dem WrapperLoop und dem FuncLoop wird vor allem dann klar wenn man das Skip und Take mehrfach ausführt. Hier habe ich es einfach 10-mal laufen lassen. Der SimpleLoop benötigt immer 9 Add Aufrufe und damit bleibt er immer gleich. Beim YieldLoop werden 4 x 10 nötig und beim FuncLoop 2 x 10. Lediglich der WrapperLoop führt nur 2 Aufrufe durch.

SimpleLoop start

927,8073

SimpleLoop end

CallYieldLoop start

4025,9645

CallYieldLoop end

CallSimpleFuncLoop start

2022,8212

CallSimpleFuncLoop end

CallWrapperFuncLoop start

205,7986

CallWrapperFuncLoop end

Vieles hat LINQ mit sich gebracht, so auch yield return. Eigentlich gar nichts Neues wenn man sich das Feature vereinfacht als Delegate vorstellt. Wie bei jeder Technologie sollte man sich vor Augen welche Restriktionen sie mit sich bringt. Im Falle von LINQ ist es sehr oft der mehrfache Zugriff auf vermeintlich dasselbe Objekt, nur durch ein Statement kann die Performance sehr schnell ganz schlecht werden. Neben der Zeit gibt es auch andere Performancecounter, die negative beeinflusst werden könnten. Wären x und y beispielsweise große Businessobjekte oder Buffer, so würde beim SimpleLoop nur das Ergebnis übernommen aber x und y durch die Garbagecollection abgeräumt werden. Beim YieldLoop müssen jedoch für jedes Item (Delegate) x und y vorgehalten werden und können erst abgeräumt werden wenn die IEnumerable<int> nicht mehr benötigt wird. Beim WrapperLoop könnte man dies beispielsweise darüber lösen m_getData nach dem Laden auf null zu setzen.

MSBuild Solution (sln)

Hier ein paar Tips und Tricks wie man den Build von Visual Studio und per MSBuild.exe vereinheitlicht.

Man kann zwar die Solution über eine MSBuild Task erstellen, dafür benötigt man aber ein separates Buildfile. Leider kennt aber Visual Studio dieses File nicht und wird es nicht ausführen.

<MSBuild Projects="abc.sln" Properties="Configuration=Debug;Plattform=Any CPU"/>

Heißt alle Besonderheiten werden nicht im Visual Studio Build durchgeführt. Um nun alle gewünschten Verarbeitungen zu integrieren kann man die Solution erweitern. Als erstes ruft man MSBuild mit der Solution auf:

msbuild.exe abc.sln /p:Configuration=Debug;Platform=Any CPU

Wählt man keine Configuration und Platform, so wird die im Solutionfile hinterlegte verwendet. Genauso kann man über /t:target noch den entsprechenden Build ausführen. Nun arbeiten der Build und Visual Studio auf den gleichen Dateien. Das Solutionfille ist aber kein MSBuildfile, es wird aber darin umgewandelt. Mit

set msbuildemitsolution=1
msbuild.exe abc.sln

wird dieses auch auf der Platte abgelegt. Wirft man einen Blick hinein, so findet man

<Import Projects="before.abc.sln.targets" Condition="exists(‘before.abc.sln.targets’)"/>
<Import Projects="after.abc.sln.targets" Condition="exists(‘after.abc.sln.targets’)"/>

Man kann also den Build anpassen indem man neben dem Solutionfile Dateien mit entsprechenden Namen anlegt. Diese werden auch von Visual Studio, ausgenommen von den Versionen 2010 und 2012, ausgeführt.

Ein Build über die Commandline und aus Visual Studio laufen damit auf den gleichen Dateien. Ein Fehler in den Buildfiles fällt somit nicht erst bei einem automatisierten Build auf. Leider konnte ich noch nicht prüfen ob auch im TFS die before und after target ausgeführt werden.

Kovarianz und Kontravarianz

So hochtrabend die Bezeichnung Kovarianz und Kontravarianz klingt, so simpel und alt, sehr alt, ist die Idee dahinter.

Spezialisierung und Generalisierung sind Grundkonzepte der Objektorientierten Programmierung. Wie in Zeile 8 aufgezeigt, konnte man schon immer eine spezialisierte Instanz einer Klasse einer generalisierten Variable zuweisen.

   1: public class Control {}

   2: public class ItemContainer : Control{}

   3: public class Item : Control{}

   4:  

   5: public static void Main()

   6: {

   7:     Item i = new Item();

   8:     Control c = Do(i);

   9: }

  10:  

  11: public static ItemContainer Do(Control arg)

  12: {

  13:     ...

  14:     return new ItemContainer();

  15: }

Delegates gab es zwar schon vor LINQ, jedoch erlebten sie damit einen Hype. Folgendes konnte man schon immer tun:

   1: Item i = new Item();

   2: Func<Control, ItemContainer> do = arg => Do(arg);

   3: Control c = do(i);

Im Zusammenhang mit LINQ werden Delegates aber sehr oft selbst als Parameter für Methodenaufrufe verwendet. Nun kommen Kovarianz und Kontravarianz zum Einsatz:

   1: Item i = new Item();

   2: Func<Control, ItemContainer> do = arg => Do(arg);

   3: Func<Control, Control> doGeneral = do;

   4:  

   5: Control c = doGeneral(i);

Während folgende Zuweisungen den gewünschten Effekt haben,

   1: string[] sItems = new string[]{ "abc", "123"};

   2: object[] oItems = sItems;

   3:  

   4: IEnumerable<string> sEnumerable = sItems;

   5: IEnumerable<object> oEnumerable = sEnumerable

führt Zeile 2 zum Fehler. Verständlicherweise zum Fehler, denn man könnte oItems.Add mit beliebigen Argumenten aufrufen.

   1: IList<string> sItems = new string[]{ "abc", "123"};

   2: IList<object> oItems = sItems;

Trotzdem würde ich mir wünschen, dass Microsoft nicht nur Delegates und IEnumerable<> mit dem Feature versieht. Sondern beispielsweise auch:

   1: public interface IControl { }

   2:  

   3: public interface IItemContainer

   4: {

   5:     IEnumerable<IControl> Controls { get; }

   6: }

   7:  

   8: public class Control : IControl {}

   9:  

  10: public class ItemContainer : Control, IItemContainer

  11: {

  12:     public IList<Control> Controls { get; }

  13: }

Der Code  wird witzigerweise erst lauffähig mit folgender Erweiterung:

   1: public class ItemContainer : Control, IItemContainer

   2: {

   3:     public IList<Control> Controls { get; set; }

   4:  

   5:     IEnumerable<IControl> IItemContainer.Controls

   6:     {

   7:         get { return this.Controls; }

   8:     }

   9: }

Für mich leider unverständlich, denn IList implementiert IEnumerable und dort ist eine Generalisierung erlaubt.

Während die Grundkonzepte der OOP für LINQ auf Delegates und IEnumerable eingeführt wurden, ist mir unverständlich warum sie nicht auch für das obige Beispiel gelten. Mir ist klar dass IEnumerable nicht die Sicht auf die Liste ändert sondern nur durch Enumerator.Current die Sicht auf ein Item, aber dies tut IItemContainer auch. Man muss bei der expliziten Implementierung nicht mal casten!

Close existing Connections by SQL Script

Beim Löschen einer Datenbank kann man “close existing connections” auswählen. Beim Restore oder Detach kann man es leider nicht, hier bekommt man nach längerem Warten eine Fehlermeldung.

Die wohl bekannteste Möglichkeit Verbindungen zuschließen bietet der Activity Monitor. Hier sieht man alle Prozesse, diese kann man filtern und den gewünschten schließen. Leider nur einen Prozess nach dem anderen. Bei zu vielen Prozessen braucht man unter Umständen recht lange und läuft Gefahr dass in der Zwischenzeit wieder neue Verbindungen erstellt wurden.

ActivityMon1

ActivityMon2

Man kann aber auch per Script alle Verbindungen außer der eigenen schließen, indem man KILL verwendet:

   1: DECLARE @dbName AS VARCHAR(200) = 'xyz'; -- DB_NAME()

   2:  

   3: DECLARE @kill AS VARCHAR(max) = '';

   4: SELECT @kill = @kill + 'KILL ' + STR([SPID]) + ';'

   5: FROM master..sysprocesses 

   6: WHERE [DBID] = DB_ID(@dbName)

   7: AND [SPID] <> @@SPID;

   8:  

   9: EXEC(@kill);

Leider erlebe ich es oft, dass die Testumgebung blockiert ist und ein Update auf eine neue Version verhindert. Dann kommt man leider nicht dran vorbei alle Verbindungen zu schließen.

 

Ich persönlich lege solche Scripte ungern in der Datenbank ab, da sie meist in Produktion nicht benötigt werden. Besser finde ich es sie als Toolset zu sammeln. Dies kann man zusammen mit den Sourcen des Projektes oder als Teil des Projektes einchecken.