<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3377869834318369205</id><updated>2024-08-30T01:55:32.654-07:00</updated><category term="C# DotNet batch processing large amounts data speed threads multithreading semaphore"/><category term="C# DotNet string enumerator enumerate"/><category term="c#"/><category term="central"/><category term="fast copy MS Access ODBC C# dotnet COM"/><category term="fast data copy sql server ms access"/><category term="logger"/><category term="logging"/><category term="observer"/><category term="pattern"/><category term="powerful"/><category term="simple"/><category term="singleton"/><title type='text'>Cooking with C#</title><subtitle type='html'>Some C# technical articles designed to help developers out there. A way to return the favor to all those whose articles bailed me out :)</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-5188243104231175221</id><published>2008-01-10T07:42:00.000-08:00</published><updated>2008-01-10T07:48:22.945-08:00</updated><title type='text'>It&#39;s all about the looks ...</title><content type='html'>&lt;span style=&quot;color:#000000;&quot;&gt;Would you be enthusiatic about a Lada, even if the salesman proved it had the engine of a Ferrari? Probably not.&lt;br /&gt;&lt;br /&gt;Same goes for software. The user interface says a lot about the application, and in many cases, can easily make up for quirky behaviour and simple bugs. Your customer will always see the interface first and give his first impressions based on it, so it&#39;s extremely important.&lt;br /&gt;&lt;br /&gt;So the next big thing for interfaces seems to be WPF. I started looking into it, and it looks quite promissing. Visual Studio 2008 has a pretty good editor for it, so it&#39;s a good idea to get into it.&lt;br /&gt;&lt;br /&gt;For those just starting out, I found a very good (albeit lengthy) hands-on lab that guides you through the steps of putting together an Outlook clone with WPF.&lt;br /&gt;&lt;br /&gt;The lab can be found here: &lt;a href=&quot;http://www.00001001.ch/download/HOL/WPF/Outlook_HOL_WPF.pdf&quot;&gt;http://www.00001001.ch/download/HOL/WPF/Outlook_HOL_WPF.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The original blog post where I found this is here: &lt;a href=&quot;http://blogs.msdn.com/tims/archive/2007/06/13/wpf-hands-on-lab-build-an-outlook-2007-ui-clone.aspx&quot;&gt;http://blogs.msdn.com/tims/archive/2007/06/13/wpf-hands-on-lab-build-an-outlook-2007-ui-clone.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/5188243104231175221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/5188243104231175221' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/5188243104231175221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/5188243104231175221'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2008/01/its-all-about-looks.html' title='It&#39;s all about the looks ...'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-3886474431296241938</id><published>2008-01-02T06:06:00.000-08:00</published><updated>2008-01-02T06:09:40.148-08:00</updated><title type='text'>C# string enumerator working flawlessly now</title><content type='html'>I was able to remove the dependency on ToString() in the string enumerator article posted a couple of days ago, so now it really is perfect. You can assign the value of the enumerator directly to a string variable without any casting or the use of ToString(), although you still can if you want to (but I don&#39;t see why you would).&lt;br /&gt;&lt;br /&gt;The article and the sample code on &lt;a href=&quot;http://www.codeproject.com/KB/cs/csharpstringenumerator.aspx&quot;&gt;CodeProject&lt;/a&gt; are both up to date now.</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/3886474431296241938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/3886474431296241938' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/3886474431296241938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/3886474431296241938'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2008/01/c-string-enumerator-working-flawlessly.html' title='C# string enumerator working flawlessly now'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-8653892179196885997</id><published>2007-12-31T11:11:00.000-08:00</published><updated>2008-01-02T05:48:05.476-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C# DotNet string enumerator enumerate"/><title type='text'>The perfect C# string enumerator</title><content type='html'>&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;I really love C# and do my utmost at kicking myself in the rear for not having gotten into it sooner than I did. In spite of that, though, I sorely miss some things from other languages.&lt;br /&gt;&lt;br /&gt;Take string enumerators for example. Enumerators are an amazing thing when it comes to keep things clean and easy to maintain. You define them once, assign them their values, and use their names throughout the program. Behind the scene each enumeration is translated to the value you set it up with, and that&#39;s what you end up storing on disk, using for calculations, etc.&lt;br /&gt;&lt;br /&gt;String enumerations are no different. You pick a set of names, assign them their text values, and in code you always refer to the names. When it comes time to using them for disk storage, display, etc., you refer to the enumeration&#39;s value.&lt;br /&gt;&lt;br /&gt;But in C#, for whatever reason (anyone know why?), this was left out. I&#39;ve looked around for quite a while, and found proposed solutions that ranged from simply creating a class with static strings to some that use reflection. They all seemed either too simple or too complex, and none gave me all the functionality an enumerator should have.&lt;br /&gt;&lt;br /&gt;So I set out to make my own, and I think I&#39;ve done it. I would say that it mimics a regular enumerator to 100%, and provides exactly the same functionality, usage and behaviour as regular enumerators. I cannot think of anything that has been missed, and am depending on my readers to help point those things out :) &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;Background&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;When I set out to create this, I had to sit down and think about all the ways in which an enumerator could be used in order to make sure the string enumerator is as true to its name as possible. I&#39;ve created a number of tests using nUnit, and so far so good. I can&#39;t really think of any more good tests for this, but if anyone else can please let me know.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;Usage&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;You can refer to the tests in the nUnit project to see the enumerator&#39;s capabilities, but here they are in brief:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Assigning a static enumerator&#39;s value to a string&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Instantiating an enumerator object, setting it to a valid enumerator value, passing it as a parameter to a method, and assigning its value to a string.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Instantiating an enumerator object, setting it to a valid enumerator value, passing it as a parameter to a method, copying that enumerator to a new one, and assigning the new enumerator&#39;s value to a string.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Same as the above, but right after copying the first enumerator to the second one, we change the first one&#39;s value and ensure the second one has not been affected. Note that although we are dealing with a reference item, the enumerator class is immutable so we are always creating a new copy when assigning it a new value. Assigning an existing object to another one is done just with the &quot;=&quot; sign, without a dependency on the iCloneable interface, and the copy is not a shallow one (although there isn&#39;t much depth to this class).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Testing enumerated strings that contain spaces&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Assigning a valid string value to an enumerator object&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Assigning an invalid string value to an enumerator object, and getting an exception&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Creating two enumerator objects, and enssuring that ==, != and Equals() perform properly.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Once you create the enumerator class, you use it exactly the way you would use a regular enumerator, with one slight difference: When you want to deal with the actual string value of either the enumerator object or of one of the static enumerator values, you must use the ToString() method. I would dearly love to find a way around this, but even if I can&#39;t, I think it&#39;s a pretty small price to pay.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;The EStringEnum base class&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;To create a string enumerator you&#39;ll need two things. The base EStringEnum class, and a class that you define (which inherits from EStringEnum) with the actual string values.&lt;br /&gt;&lt;br /&gt;The base class exposes two items that must be overwritten, as well as logic for validating string values that the user is trying to assign to an enumerator object (i.e. the value must be one of the valid enumerated strings), and some overloads for ToString() and various operators:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;/// &lt;summary&gt;&lt;br /&gt;/// A string enumerator base class. Must be inherited.&lt;br /&gt;/// &lt;/summary&gt;&lt;br /&gt;public abstract class EStringEnum&lt;br /&gt;{&lt;br /&gt;    #region Data&lt;br /&gt;    protected string mCurrentEnumValue = &quot;&quot;;&lt;br /&gt;&lt;br /&gt;    protected abstract string EnumName { get; }&lt;br /&gt;&lt;br /&gt;    protected abstract List&lt;string&gt; PossibleEnumValues { get; }&lt;br /&gt;&lt;br /&gt;    #endregion&lt;br /&gt;&lt;br /&gt;    #region Constructors&lt;br /&gt;    public EStringEnum() { }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// A string enumerator&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    /// &lt;param name=&quot;value&quot;&gt;A valid enumerator value. &lt;br /&gt;    /// An exception is raised if the value is invalid.&lt;/param&gt;&lt;br /&gt;    public EStringEnum(string value)&lt;br /&gt;    {&lt;br /&gt;        if (PossibleEnumValues.Contains(value))&lt;br /&gt;        {&lt;br /&gt;            mCurrentEnumValue = value;&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            string errorMessage = string.Format(&lt;br /&gt;                &quot;{0} is an invalid {1} enumerator value&quot;, &lt;br /&gt;                value, &lt;br /&gt;                EnumName);&lt;br /&gt;            throw new Exception(errorMessage);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    #endregion&lt;br /&gt;&lt;br /&gt;    #region Overloads&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Returns the enumerator&#39;s current value&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    /// &lt;returns&gt;&lt;/returns&gt;&lt;br /&gt;    public override string ToString()&lt;br /&gt;    {&lt;br /&gt;        return mCurrentEnumValue;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Test for equality&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    /// &lt;param name=&quot;stringEnum1&quot;&gt;&lt;/param&gt;&lt;br /&gt;    /// &lt;param name=&quot;stringEnum2&quot;&gt;&lt;/param&gt;&lt;br /&gt;    /// &lt;returns&gt;&lt;/returns&gt;&lt;br /&gt;    public static bool operator ==(EStringEnum stringEnum1, EStringEnum stringEnum2)&lt;br /&gt;    {&lt;br /&gt;        return (stringEnum1.ToString().Equals(stringEnum2.ToString()));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Test for inequality&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    /// &lt;param name=&quot;stringEnum1&quot;&gt;&lt;/param&gt;&lt;br /&gt;    /// &lt;param name=&quot;stringEnum2&quot;&gt;&lt;/param&gt;&lt;br /&gt;    /// &lt;returns&gt;&lt;/returns&gt;&lt;br /&gt;    public static bool operator !=(EStringEnum stringEnum1, EStringEnum stringEnum2)&lt;br /&gt;    {&lt;br /&gt;        return (!stringEnum1.ToString().Equals(stringEnum2.ToString()));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Test for equality&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    /// &lt;param name=&quot;o&quot;&gt;&lt;/param&gt;&lt;br /&gt;    /// &lt;returns&gt;&lt;/returns&gt;&lt;br /&gt;    public override bool Equals (object o)&lt;br /&gt;    {&lt;br /&gt;        EStringEnum stringEnum = o as EStringEnum;&lt;br /&gt;        return (this.ToString().Equals(stringEnum.ToString()));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Retrieve the hashcode&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    /// &lt;returns&gt;&lt;/returns&gt;&lt;br /&gt;    public override int GetHashCode()&lt;br /&gt;    {&lt;br /&gt;        return base.GetHashCode();&lt;br /&gt;    }&lt;br /&gt;    #endregion&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Only two things from this base class must be implemented when inheriting it:&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;protected abstract string EnumName { get; }&lt;br /&gt;protected abstract List&lt;string&gt; PossibleEnumValues { get; }&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;color:#000000;&quot;&gt;EnumName must return a string with the name of the string enumerator (e.g. ECarManufacturers), and PossibleEnumValues must return a List&lt;string&gt; of the enumerated strings (e.g. &quot;Ford&quot;, &quot;Toyota&quot;, etc).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;The actual enumerator class&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The enumerator must inherit from EStringEnum and do the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;implement the two properties mentioned above,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;provide static accessors for each enumerated string,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;provide a constructor (which just calles the base constructor), and&lt;/li&gt;&lt;br /&gt;&lt;li&gt;provide an implicit conversion from a string type to an object type of the actual enumerator (e.g. ECarManufacturers).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;It may sound complex, but as the example below shows, it really is quite simple to implement:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;/// &lt;summary&gt;&lt;br /&gt;/// A car manufacturer enumerator&lt;br /&gt;/// &lt;/summary&gt;&lt;br /&gt;public class ECarManufacturers: EStringEnum&lt;br /&gt;{&lt;br /&gt;    #region Data&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Used by EStringEnum to identify the current class&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    protected override string EnumName { get { return &quot;ECarManufacturers&quot;; } }&lt;br /&gt;&lt;br /&gt;    protected override List&lt;string&gt; PossibleEnumValues { get &lt;br /&gt;        { return mPossibleEnumValues; } }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Complete list of string values that this enumerator can hold&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    private static List&lt;string&gt; mPossibleEnumValues = new List&lt;string&gt;()&lt;br /&gt;    {&lt;br /&gt;        &quot;Toyota&quot;,&lt;br /&gt;        &quot;Honda&quot;,&lt;br /&gt;        &quot;Ford&quot;,&lt;br /&gt;        &quot;Chrysler&quot;,&lt;br /&gt;        &quot;Volvo&quot;,&lt;br /&gt;        &quot;General Motors&quot;&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// CarManufacturers type&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    static public ECarManufacturers Toyota&lt;br /&gt;    {&lt;br /&gt;        get { return new ECarManufacturers(mPossibleEnumValues[0]); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// CarManufacturers type&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    static public ECarManufacturers Honda&lt;br /&gt;    {&lt;br /&gt;        get { return new ECarManufacturers(mPossibleEnumValues[1]); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// CarManufacturers type&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    static public ECarManufacturers Ford&lt;br /&gt;    {&lt;br /&gt;        get { return new ECarManufacturers(mPossibleEnumValues[2]); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// CarManufacturers type&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    static public ECarManufacturers Chrysler&lt;br /&gt;    {&lt;br /&gt;        get { return new ECarManufacturers(mPossibleEnumValues[3]); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// CarManufacturers type&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    static public ECarManufacturers Volvo&lt;br /&gt;    {&lt;br /&gt;        get { return new ECarManufacturers(mPossibleEnumValues[4]); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// CarManufacturers type&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    static public ECarManufacturers GeneralMotors&lt;br /&gt;    {&lt;br /&gt;        get { return new ECarManufacturers(mPossibleEnumValues[5]); }&lt;br /&gt;    }&lt;br /&gt;    #endregion&lt;br /&gt;&lt;br /&gt;    #region Constructor&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// A car manufacturer enumerator&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    /// &lt;param name=&quot;value&quot;&gt;A valid enumerator value. &lt;br /&gt;    /// An exception is raised if the value is invalid.&lt;/param&gt;&lt;br /&gt;    private ECarManufacturers(string value): base(value)&lt;br /&gt;    { }&lt;br /&gt;    #endregion&lt;br /&gt;&lt;br /&gt;    #region Misc methods&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Implicitly convert a string to a CarManufacturers object&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    /// &lt;param name=&quot;value&quot;&gt;A string value to convert to an ECarManufacturers enum value.  &lt;br /&gt;    /// An exception is raised if the value is invalid.&lt;/param&gt;&lt;br /&gt;    /// &lt;returns&gt;&lt;/returns&gt;&lt;br /&gt;    public static implicit operator ECarManufacturers(string value) &lt;br /&gt;    {&lt;br /&gt;        return new ECarManufacturers(value);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Implicitly convert an ECarManufacturers object to a string&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    /// &lt;param name=&quot;carManufacturers&quot;&gt;A ECarManufacturers object whose value is to &lt;br /&gt;    /// be returned as a string&lt;/param&gt;&lt;br /&gt;    /// &lt;returns&gt;&lt;/returns&gt;&lt;br /&gt;    public static implicit operator string(ECarManufacturers carManufacturers)&lt;br /&gt;    {&lt;br /&gt;        return carManufacturers.ToString();&lt;br /&gt;    }&lt;br /&gt;    #endregion&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;Examples&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The following tests are included in the nUnit test project (available in the download), but I&#39;m posting them here as well to give you a quick look at how true-to-life this implementation is:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[TestFixture]&lt;br /&gt;public class TestClass1&lt;br /&gt;{&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test01()&lt;br /&gt;    {&lt;br /&gt;        string result = ECarManufacturers.GeneralMotors.ToString();&lt;br /&gt;        string expected = &quot;General Motors&quot;;&lt;br /&gt;        Assert.IsTrue(result == expected);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test02()&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers carManufacturer = ECarManufacturers.Honda;&lt;br /&gt;        string result = carManufacturer.ToString();&lt;br /&gt;        string expected = &quot;Honda&quot;;&lt;br /&gt;        Assert.IsTrue(result == expected);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test03()&lt;br /&gt;    {&lt;br /&gt;        Test03A(ECarManufacturers.Ford);&lt;br /&gt;    }&lt;br /&gt;    private void Test03A(ECarManufacturers carManufacturer)&lt;br /&gt;    {&lt;br /&gt;        string expected = &quot;Ford&quot;;&lt;br /&gt;        string result = carManufacturer.ToString();&lt;br /&gt;        Assert.IsTrue(result == expected);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test04()&lt;br /&gt;    {&lt;br /&gt;        Test04A(ECarManufacturers.Ford);&lt;br /&gt;    }&lt;br /&gt;    private void Test04A(ECarManufacturers carManufacturer)&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers tempCarManufacturers2 = carManufacturer;&lt;br /&gt;        string result = tempCarManufacturers2.ToString();&lt;br /&gt;        string expected = &quot;Ford&quot;;&lt;br /&gt;        Assert.IsTrue(result == expected);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test05()&lt;br /&gt;    {&lt;br /&gt;        Test05A(ECarManufacturers.Ford);&lt;br /&gt;    }&lt;br /&gt;    private void Test05A(ECarManufacturers carManufacturer)&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers carManufacturer2 = carManufacturer;&lt;br /&gt;        carManufacturer = ECarManufacturers.Chrysler;&lt;br /&gt;        string expected1 = &quot;Chrysler&quot;;&lt;br /&gt;        string result1 = carManufacturer.ToString();&lt;br /&gt;        string expected2 = &quot;Ford&quot;;&lt;br /&gt;        string result2 = carManufacturer2.ToString();&lt;br /&gt;        Assert.IsTrue(result1 == expected1 &amp;&amp; result2 == expected2);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test06()&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers tempCarManufacturers = &quot;Ford&quot;;&lt;br /&gt;        string result = tempCarManufacturers.ToString();&lt;br /&gt;        string expected = &quot;Ford&quot;;&lt;br /&gt;        Assert.IsTrue(result == expected);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test07()&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers tempCarManufacturers2 = null;&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            tempCarManufacturers2 = &quot;Orion&quot;;&lt;br /&gt;            Assert.Fail();&lt;br /&gt;        }&lt;br /&gt;        catch (Exception ex)&lt;br /&gt;        {&lt;br /&gt;            Assert.IsTrue(ex.Message.Equals(&lt;br /&gt;                &quot;Orion is an invalid ECarManufacturers enumerator value&quot;));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test08()&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers tempCarManufacturers = &quot;General Motors&quot;;&lt;br /&gt;        Assert.IsTrue(tempCarManufacturers.ToString().Equals(&lt;br /&gt;            ECarManufacturers.GeneralMotors.ToString()));&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test09()&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers carManufacturers1 = ECarManufacturers.GeneralMotors;&lt;br /&gt;        ECarManufacturers carManufacturers2 = ECarManufacturers.GeneralMotors;&lt;br /&gt;        Assert.IsTrue(carManufacturers1 == carManufacturers2);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test10()&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers carManufacturers1 = ECarManufacturers.GeneralMotors;&lt;br /&gt;        ECarManufacturers carManufacturers2 = ECarManufacturers.Ford;&lt;br /&gt;        Assert.IsTrue(carManufacturers1 != carManufacturers2);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test11()&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers carManufacturers1 = ECarManufacturers.GeneralMotors;&lt;br /&gt;        int number = carManufacturers1.GetHashCode();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test]&lt;br /&gt;    public void Test12()&lt;br /&gt;    {&lt;br /&gt;        ECarManufacturers carManufacturers1 = ECarManufacturers.GeneralMotors;&lt;br /&gt;        string value = carManufacturers1;&lt;br /&gt;        ECarManufacturers carManufacturers2 = carManufacturers1;&lt;br /&gt;        string value2 = carManufacturers2;&lt;br /&gt;        Assert.IsTrue(value.Equals(&quot;General Motors&quot;));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;In conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Not a very complex solution when you think about it, and I think it covers all the behaviours an enumerator is expected to have. When it comes time to use the enumerator, you use it exactly like you would use a regular enumerator. If you can think of anything I&#39;ve missed or can improve upon, feel free to tell me.&lt;br /&gt;&lt;br /&gt;Something I&#39;d like to do to improve on this are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Extract as much logic as possible and put it in the base class (such as the static accessors). I could use something like Spring.Net to inject the accessors at runtime, but this would have two major drawbacks: intellisense would no longer work, and I would be adding a dependency to the project.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;A downloadable copy of the source code is available here: &lt;a href=&quot;http://www.codeproject.com/KB/cs/csharpstringenumerator.aspx&quot;&gt;http://www.codeproject.com/KB/cs/csharpstringenumerator.aspx&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;History&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;December 31 2007 - Initial post (happy new year!).&lt;br /&gt;January 01 2008 - Added examples.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/8653892179196885997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/8653892179196885997' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/8653892179196885997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/8653892179196885997'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/12/999-c-string-enumerator.html' title='The perfect C# string enumerator'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-9058736932004521785</id><published>2007-12-29T09:30:00.001-08:00</published><updated>2007-12-29T09:37:10.630-08:00</updated><title type='text'>The search for string enumerators</title><content type='html'>&lt;span style=&quot;color:#000000;&quot;&gt;Of all the languages I&#39;ve worked with so far, C# is by far my favourite. My list of reasons for this is quite long, but in spite of all that, I still have things I enjoyed very much in other languages that C# lacks. Simple examples are Cobol&#39;s EVALUATE statement and Visual Basic&#39;s string enumerators.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Under the hood, the EVALUATE statement is the equivalent of a series of &lt;em&gt;else if&lt;/em&gt; statements, except that the debugger does a very elegant job of jumping straight to the else path that is true instead of stepping through every single one until it finds one that it likes. Not a big deal, but certainly something I miss.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The string enumerator, on the other hand, is sorely missed. I have yet to find a good way to implement one in C#, and so am embarking on a mission. I&#39;ve seen several suggestions out there, ranging from simple ones that use string formatting to extract the names of  an integer enumerator to more complex ones that use reflection. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Suffice it to say that I didn&#39;t like any of them. Too simple, too inelegant, etc. There has to be a good way out of this that will not be too complex to implement, will be elegent to code and use, and will resemble the normal enumerators as much as possible (preferably to 100%).&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/9058736932004521785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/9058736932004521785' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/9058736932004521785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/9058736932004521785'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/12/search-for-string-enumerators.html' title='The search for string enumerators'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-8401002841006707948</id><published>2007-12-28T18:27:00.000-08:00</published><updated>2007-12-28T18:32:19.657-08:00</updated><title type='text'>If you need to do asynchronous work, this is for you ...</title><content type='html'>&lt;span style=&quot;color:#000000;&quot;&gt;I read a good article by Mike Peretz on the codeproject about delegates and asynchronous method invocation. It&#39;s a good thing to know, especially if you have work that takes a while to complete, have a UI that needs to remain fresh while doing some heavy work (although you should probably be using an MVP pattern - which takes care of this - if your app has a front end and complex business logic), etc.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;You can read the article here:&lt;/span&gt; &lt;a href=&quot;http://www.codeproject.com/KB/cs/AsyncMethodInvocation.aspx&quot;&gt;http://www.codeproject.com/KB/cs/AsyncMethodInvocation.aspx&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/8401002841006707948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/8401002841006707948' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/8401002841006707948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/8401002841006707948'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/12/if-you-need-to-do-asynchronous-work.html' title='If you need to do asynchronous work, this is for you ...'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-398014709587250358</id><published>2007-12-27T18:23:00.000-08:00</published><updated>2007-12-28T04:59:43.148-08:00</updated><title type='text'>Excellent article on distributed computing</title><content type='html'>&lt;span style=&quot;color:#000000;&quot;&gt;I came across this article by Daniel Vaughan in the code project about making your own distributed computing application, similar to what BOINC does with Seti@home only through a browser. Well written and pretty interesting. Should be a good read to anyone interested in this stuff, or is just looking for something new and cool.&lt;br /&gt;&lt;br /&gt;Check it out at &lt;a href=&quot;http://www.codeproject.com/KB/silverlight/gridcomputing.aspx&quot;&gt;http://www.codeproject.com/KB/silverlight/gridcomputing.aspx&lt;/a&gt;.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/398014709587250358/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/398014709587250358' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/398014709587250358'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/398014709587250358'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/12/excellent-article-on-distributed.html' title='Excellent article on distributed computing'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-8153114613955807842</id><published>2007-12-26T14:51:00.000-08:00</published><updated>2007-12-26T14:52:26.160-08:00</updated><title type='text'>Ok, seems like it&#39;s all fixed now.</title><content type='html'>These templates can be a pain to work with, but it seems to be over now. On to the next article, then!</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/8153114613955807842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/8153114613955807842' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/8153114613955807842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/8153114613955807842'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/12/ok-seems-like-its-all-fixed-now.html' title='Ok, seems like it&#39;s all fixed now.'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-3646261372099453961</id><published>2007-12-26T04:03:00.001-08:00</published><updated>2007-12-26T04:04:05.682-08:00</updated><title type='text'>Major blog issues ...</title><content type='html'>I have no idea why, but blogspot has serious issues with their templates. The site&#39;s proper layout will be up and running in the next day or two.</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/3646261372099453961/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/3646261372099453961' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/3646261372099453961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/3646261372099453961'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/12/major-blog-issues.html' title='Major blog issues ...'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-4261008238306891710</id><published>2007-12-10T19:46:00.001-08:00</published><updated>2007-12-13T18:55:33.208-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C# DotNet batch processing large amounts data speed threads multithreading semaphore"/><title type='text'>Faster batch processing of large amounts of data</title><content type='html'>&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;I frequently come across the need to process large amounts (i.e. in the hundreds of thousands or even millions) of repetitive pieces of data such as records from a database table or a collection of objects, apply some business transformation, and them save them (e.g. rewrite them to the database, generate a report, etc.)&lt;br /&gt;&lt;br /&gt;In a simple database example you could just write an SQL statement that does an UPDATE of the affected records based on certain selection criteria (as specified by the WHERE clause). This is a pretty limited way of doing things, however, and if you start getting into complex situations you might end up using cursors which are a whole other can of worms. So if you start performing the update in code, you are automatically obliged to get a DataReader, read the records one by one, apply your business logic, and the rewrite the results. For various reasons, this is very time consuming.&lt;br /&gt;&lt;br /&gt;A non-database related example could be a collection holding several million objects that all need to be manipulated somehow. You will undoubtedly use a foreach() loop and handle the objects one by one, but this again is an inefficient use of CPU power. You can do better.&lt;br /&gt;&lt;br /&gt;This article describes a very efficient and scalable mechanism for processing such large amounts of data. It uses multiple concurrent threads to handle small batches of work, and can take advantage of multiple core CPUs by creating more threads depending on how many cores there are.&lt;br /&gt;&lt;br /&gt;A demo project is available at the codeproject. It creates 5,000,000 customer objects that hold basic information such as an ID and a name, updates a discount percentage for each, and reverses the customer name 50 times (just so we have something time consuming to do). It was run on my machine (which has a quad-core CPU) for a benchmark and produced the following processing times: &lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Single thread execution: 5 minutes and 20 seconds. &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Multiple thread execution (running two threads per CPU): 2 minutes and 40 seconds. &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;span style=&quot;color:#000000;&quot;&gt;You pick the winner.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Batch processing the old fashioned way&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;As stated in the introduction, you could process a batch of objects (or records) one at a time, by using a foreach() loop and handling the objects in that loop one at a time. Some of the advantages to this method are that it’s easier to understand the code and you don’t have to deal with threading. That having being said, the code can be perfectly understood if it’s well documented (which it should be!), and if you’re processing large amounts of data you should already be familiar with threading and should be using it by now. If you’re not, then get on it.&lt;br /&gt;&lt;br /&gt;A simple one-batch example:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;class CustomerMaintenance&lt;br /&gt;{&lt;br /&gt;   // a collection of Custoemr objects that we need to process&lt;br /&gt;   List&lt;customer&gt; mCustomerList;&lt;br /&gt;&lt;br /&gt;   // Constructor. User passes in the collection of Customer&lt;br /&gt;   // objects to process.&lt;br /&gt;   public CustomerMaintenance (List&lt;customer&gt; customerList)&lt;br /&gt;   {&lt;br /&gt;      mCustomerList = customerList;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // Update method applies all the business transformations&lt;br /&gt;   // to the Custoemr objects, one at a time.&lt;br /&gt;   public void Update()&lt;br /&gt;   {&lt;br /&gt;      foreach (Customer customerToUpdate in mCustomerList)&lt;br /&gt;      {&lt;br /&gt;         customerToUpdate.Discount *= 1.10;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;color:#000000;&quot;&gt;In this example, a list of Customer objects is passed down to a CustomerMaintenance class. The Update() method is then executed, and it just applies some changes to every single object in the list. This is a very simple example since the foreach() loop could very well contain much more complex code. It is that update code which will slow you down if you’re doing something complex.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Batch processing with concurrent threads&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The biggest flaw in the example above is that it does not take advantage of multiple core CPUs, and is most definitely not scalable. If you compare the execution time between a single core and a multiple core machine running this code you might find a faster time on the latter, but it will not be a big difference. Moreover, the difference would most probably be due to a faster CPU, more RAM, or some other such factor. The biggest weapon in your arsenal - the extra CPUs - will just remain unused and untapped.&lt;br /&gt;&lt;br /&gt;So here’s how you do it. Processing you data in concurrent threads involves several steps:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;color:#663333;&quot;&gt;Step 1 - Assigning key values to each object&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The first thing we need is the ability to refer to each object by a key value. When we launch the thread workers, we will not be passing them a batch containing all the objects to be handled. Rather, all those objects will remain in one collection visible to all the thread workers, and each worker will be working on distinct objects within this list, which they will access by a key.&lt;br /&gt;&lt;br /&gt;Coming up with these keys is slightly different when working with objects as opposed to database records. If you’re dealing with a list of objects, you can either choose a property that will be unique amongst all those objects (such as the customer ID), or if you do not have such a property, you can simply use an incremental counter (which does not necessarily need to be a property of the objects).&lt;br /&gt;&lt;br /&gt;To work with objects, simply declare a SortedList&lt;key,&gt; where the key is that unique property and the object is the type of object you will be working with. Load the SortedList with all the keys and values, and you’re set to go. This is the shared collection of data that all worker threads will be updating. Next, create a List&lt;key&gt; that contains all the keys from that shared collection, and this becomes the pool from which all threads will receive their individual batches of work.&lt;br /&gt;&lt;br /&gt;For example:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;// Shared collection, containing all the objects to update&lt;br /&gt;SortedList&lt;long,&gt; mCustomerList mCustomerList =&lt;br /&gt;new SortedList&lt;long,&gt;();&lt;br /&gt;&lt;br /&gt;// code to populate the dictionary with the Customer objects goes here&lt;br /&gt;&lt;br /&gt;// Create a list of keys containing all key values to the shared&lt;br /&gt;// collection. This becomes a sort of index.&lt;br /&gt;List&lt;long&gt; allCustomerIDs = new List&lt;long&gt;(mCustomerList.Keys);&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;color:#000000;&quot;&gt;If, however, you’re dealing with database records, you will need to use a key field in your SELECT statement. Assuming you are going to issue an UPDATE on all customer records in a customer table, you should first issue a SELECT statement retrieving all the customer IDs that will be affected, and then store those IDs in a List&lt;key&gt;. Just like with the object example above, this list then becomes the pool from which all threads will receive their individual batches of work. Contrary to the previous example, though, the individual threads will be updating records directly in the database, which is the equivalent of the shared collection of data used above.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;color:#663333;&quot;&gt;Step 2 - Preparing a semaphore&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;A semaphore (you will need to reference System.Threading for this one) is a very simple yet crucial element. It will control how many running thread workers we currently have, and when one has finished its work and exited, the semaphore will let us know that we can launch another worker. Semaphores are quite configurable, and you can easily specify how many requests it can handle.&lt;br /&gt;&lt;br /&gt;For example:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;// This will create a semaphore that helps control&lt;br /&gt;// as many thread launches as we need to.&lt;br /&gt;Semaphore mSemaphore = new Semaphore(numberOfThreadsToUse, numberOfThreadsToUse)&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;color:#663333;&quot;&gt;Step 3 - Looping through the list of keys and dispatching work in batches&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Now comes the fun part. We loop while the list of keys created in step 1 contains data, and do the following: &lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Wait until the semaphore has a free resource. &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Reserve a resource in the semaphore. &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Copy a predetermined number of items from keys list to a work list that will be passed down to the thread worker. &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Remove those same keys from the keys list so they are not dispatched for processing a second time. &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Launch the thread worker, passing it the work list. The thread will apply the business rules and modifications to the objects in the shared main list that are indexed by the key values passed down to it. &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;When the thread worker is done, it releases the semaphore resource (thereby enabling the launch of another thread worker) and exits. &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;p&gt;&lt;/span&gt;&lt;/p&gt;&lt;span style=&quot;color:#000000;&quot;&gt;For example:&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;private void UpdateAllCustomersInConcurrentBatches()&lt;br /&gt;{&lt;br /&gt;    // retrieve the number of CPUs on this machine, and calculate the total number&lt;br /&gt;    // of threads we should run.&lt;br /&gt;    ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(&quot;select * from Win32_Processor&quot;);&lt;br /&gt;    ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();&lt;br /&gt;    int numberOfCpus = managementObjectCollection.Count;&lt;br /&gt;    int numberOfThreadsToUse = numberOfCpus * mMaxNumberOfThreadsPerCpu;&lt;br /&gt;    int batchSize = 5000;&lt;br /&gt;&lt;br /&gt;     // get a list of all the key values to process&lt;br /&gt;    List&lt;long&gt; allCustomerIDs = new List&lt;long&gt;(mCustomerList.Keys);&lt;br /&gt;    while (allCustomerIDs.Count &gt; 0)&lt;br /&gt;    {&lt;br /&gt;        // make of list of customer IDs to process in the next batch&lt;br /&gt;        List&lt;long&gt; customerIDsToProcess = allCustomerIDs.GetRange(0, System.Math.Min(batchSize, allCustomerIDs.Count));&lt;br /&gt;        // remove those customer IDs from the master list so they are not processed again&lt;br /&gt;        allCustomerIDs.RemoveRange(0, System.Math.Min(batchSize, allCustomerIDs.Count));&lt;br /&gt;&lt;br /&gt;        // wait for the semaphore to let us launch another thread&lt;br /&gt;        mSemaphore.WaitOne();&lt;br /&gt;&lt;br /&gt;        // launch a thread worker and give it the list of customer IDs to process&lt;br /&gt;        ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateAllCustomersInSubBatch), customerIDsToProcess);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // ensure all threads have exited by waiting until we can get all the semaphore requests&lt;br /&gt;    for (int ctr = 0; ctr &lt; numberOfThreadsToUse; ctr++)&lt;br /&gt;    {&lt;br /&gt;         mSemaphore.WaitOne();&lt;br /&gt;    }&lt;br /&gt;    mSemaphore.Release(numberOfThreadsToUse);&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;color:#663333;&quot;&gt;Step 4 - processing a batch of records in a thread worker&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The method to process the records will be launched in step 3, and will receive the list of keys to work with. It will then use a foreach() loop to go through them, and using each key in the loop, access a Customer object in the shared collection and apply the appropriate business rules and changes to it.&lt;br /&gt;Similarly, if you are working with database records you would use this key value to issue a SELECT statement for one record in the table, fetch it, update it, and write it back (or maybe just issue an UPDATE statement).&lt;br /&gt;For example:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;private void UpdateAllCustomersInSubBatch(object state)&lt;br /&gt;{&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        List&lt;long&gt; customerIDsToProcess = state as List&lt;long&gt;;&lt;br /&gt;        foreach (long customerID in customerIDsToProcess)&lt;br /&gt;        {&lt;br /&gt;            Customer tempCustomer = mCustomerList[customerID];&lt;br /&gt;            // a foreach item cannot be passed down by reference, so pass&lt;br /&gt;            // a copy.&lt;br /&gt;            ApplyBusinessRulesToCustomerObject(ref tempCustomer);&lt;br /&gt;            Lock (mLock)&lt;br /&gt;            {&lt;br /&gt;            mCustomerList[customerID].Discount = tempCustomer.Discount;&lt;br /&gt;            mCustomerList[customerID].Name = tempCustomer.Name;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    catch (Exception ex)&lt;br /&gt;    {&lt;br /&gt;        lock (mLock)&lt;br /&gt;        {&lt;br /&gt;            // An exception was raised. This thread has no access to the UI, so store the exception in&lt;br /&gt;            // mExceptions and get out.&lt;br /&gt;            mExceptions.Add(ex);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    finally&lt;br /&gt;    {&lt;br /&gt;        // The work in this thread is complete. Release the semaphore request so that it can be reused to&lt;br /&gt;        // launch another thread worker for the next batch.&lt;br /&gt;        mSemaphore.Release();&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;A note about exceptions&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;An important thing to note about threads is that you have to be careful with exceptions. In a single threaded application, exceptions will be available to all the objects up the execution path, and you can therefore trap and handle them at any point.&lt;br /&gt;&lt;br /&gt;In a multithreaded application, however, exceptions will only go up as high as the first method to execute in that thread. If you do not have any try/catch blocks to handle the exceptions before (or on) that point, you’ll get an “unhandled exception” error, and the application will stop when the exception is raised.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;To get around this, the demo uses a List&lt;exception&gt; collection to store any and all exceptions raised during the thread’s execution. When we’re done looping through the main list of object keys, we can check this collection for content, and if there are any exceptions they can be sent back to form, logged, etc. Additionally, we could alter the main dispatching foreach() loop (described in step 3) to stop dispatching new batches of work if the exception collection’s count is greater than zero.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;A note about thread safety and locking&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;It’s also important to note that since multiple threads will be accessing and modifying the same objects (e.g. the shared object list and the exception collection), we need to protect against corruption and ensure that only one thread at a time has access to the shared resources. To do this, we use the lock() command which ensures that only one thread at a time can access the code in the lock block and therefore only one thread at a time can update this hared resource.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;In conclusion&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Splitting up massive amounts of repetitive work into smaller batches and processing them in parallel is simply a must-have when it comes to processing large amounts of data. The benchmark I show in the introduction shows how you can easily save 50% of your execution time, although the savings will largely be determined by the exact type of transformations you need to make to the data, and how the code is implemented.&lt;br /&gt;&lt;br /&gt;Still, I think this is a time saver that cannot be ignored, and I hope it helps someone out there.&lt;br /&gt;&lt;br /&gt;A sample project is available for testing here: &lt;a id=&quot;ctl00_MC_ArticlePath&quot; href=&quot;http://www.codeproject.com/KB/cs/FasterBatchProcessingWith.aspx&quot;&gt;http://www.codeproject.com/KB/cs/FasterBatchProcessingWith.aspx&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/4261008238306891710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/4261008238306891710' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/4261008238306891710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/4261008238306891710'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/12/faster-batch-processing-of-large.html' title='Faster batch processing of large amounts of data'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-1064122894588877196</id><published>2007-12-03T18:16:00.000-08:00</published><updated>2007-12-03T18:22:51.130-08:00</updated><title type='text'>Upcoming article - speeding up processing of large amounts of data</title><content type='html'>&lt;span style=&quot;color:#000000;&quot;&gt;One of the things I come across quite often is the need to process large amounts of data, apply certain business rules to it, and then write it back to the database it came from.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;If the business rules to be applied are not too complex, you can either generate an SQL UPDATE statement that will do the job or use a stored procedure with that same UPDATE statement. That&#39;s your best bet.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;If, however, the logic is complex and better represented in code, then you&#39;re probably stuck creating a data reader, looping through the records, and changing them one at a time. You could simply do this as described and let it take as long as it takes, or you could take advantage of threading to split the job into mutilple concurrent jobs.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Managing these worker threads through a semaphore, creating and maintaining a work queue, dispatching the work units, handling exceptions ... all this will be in the next article.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/1064122894588877196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/1064122894588877196' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/1064122894588877196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/1064122894588877196'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/12/upcoming-article-speeding-up-processing.html' title='Upcoming article - speeding up processing of large amounts of data'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-6850190058972414812</id><published>2007-11-29T09:04:00.000-08:00</published><updated>2007-11-29T09:08:22.099-08:00</updated><title type='text'>Dynamically creating DSN entries</title><content type='html'>&lt;span style=&quot;color:#000000;&quot;&gt;There&#39;s a good article about creating dynamic DSN entries, which can be put together with the blog I wrote about &lt;/span&gt;&lt;a href=&quot;http://cookingwithcsharp.blogspot.com/2007/11/how-to-quickly-copy-tables-from-odbc.html&quot;&gt;&lt;span style=&quot;color:#3333ff;&quot;&gt;copying tables to MS Access&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color:#000000;&quot;&gt;. This way you don&#39;t need to create the DSN manually, and can also clean up when the copy is done by automatically removing the DSN entry. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;&lt;br /&gt;The article is here: &lt;/span&gt;&lt;a href=&quot;http://www.codeproject.com/cs/database/DSNAdmin.asp&quot;&gt;&lt;span style=&quot;color:#3333ff;&quot;&gt;http://www.codeproject.com/cs/database/DSNAdmin.asp&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color:#3333ff;&quot;&gt; &lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/6850190058972414812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/6850190058972414812' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/6850190058972414812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/6850190058972414812'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/11/dynamically-creating-dsn-entries.html' title='Dynamically creating DSN entries'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-183614437741572348</id><published>2007-11-27T20:59:00.001-08:00</published><updated>2007-11-28T18:00:34.486-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fast copy MS Access ODBC C# dotnet COM"/><title type='text'>How to quickly copy tables from an ODBC source to MS Access within a C# project</title><content type='html'>&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;In a recent project I worked on, I ran across a pretty serious problem that seemingly had no solution. The problem was simple: I needed to copy a fairly large amount of table from a table in an SQL Server database to a table in an MS Access database. No matter which approach I followed, however, the speeds at which the copy was being executed were far too low and simply unacceptable.&lt;br /&gt;&lt;br /&gt;My frame of reference was MS Access itself, which has the ability to import tables from an ODBC source. When I compared the time it took to perform this import, it consistently beat the other tests by a wide margin of at least twenty to one.&lt;br /&gt;&lt;br /&gt;It sounds huge. I know. I do not have the exact times it took for each of the tests, but they were all much longer than doing a simple import through&lt;/span&gt;&lt;span style=&quot;color:#000000;&quot;&gt; MS Access. The comparison tests I conducted were:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Using Enterprise Manager &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Using SQL &lt;/span&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Server Management Studio &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Using SQL Server Information Services &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Using BCP (although this can only export to a text file or SQL Server binary file). The BCP process alone was able to match the time record achieved by the MS Access import, but useless since it could not export to MS Access. &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The ultimate solution, then, was to find a way to have MS Access perform the copy all the while running within a C# project. The biggest problem with this was that including support for MS Access in a .NET project automatically means including COM, and a lot of people cringe at the thought. This article, then, discusses the implementation of an SQL server to MS Access copy process that is performed by MS Access, runs within a C# project, and minimizes the impact COM has on the overall application by using late binding.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Embedding a COM object in .NET &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It isn’t pretty, but it’s possible. It will make your setup and installation more complex, but will add functionality that may otherwise not be available from within the .NET framework. The bottom line is that it is up to you on whether you want to include COM support in your project, and you’ll have to weigh the pros and cons and then decide.&lt;br /&gt;&lt;br /&gt;In my case, there wasn’t much of a choice. I could either leave my project spic and span and let the copy take almost an hour, or find an elegant way to implement COM and shrink the copy process down to a couple of minutes. The choice was pretty clear.&lt;br /&gt;&lt;br /&gt;There are basically two ways to use a COM object in your project:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;Early binding &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In this case, you add a reference to the COM object in question to your project, and benefit from the fact that Visual Studio can (in some cases) offer intellisense on the classes, methods and properties of this object. For screen controls, you also get the ability to add them to your forms in the screen designer. On the down side, however, you can no longer just copy the project files from your bin\debug or bin\release folder to another machine and run the program. You now need a setup project that will copy and register the COM controls on the target machine as well as copy your project files.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;Late binding &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you are guaranteed that the COM object in question is already installed on the target computer, and can do away with such niceties as intellisense, you can write your code so that it hooks up to the already-installed COM control and use it in pretty much the same way. The down side, obviously, is that you are not guaranteed your code will always work (because you cannot be 100% certain the COM object is already installed on the target machine), and you will not have access to intellisense or the screen designer.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Importing a table &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When importing a table into MS Access, the application lets you do so by going to File\Get external data\Import. You then choose a source such as an ODBC connection, select the database and table, and that’s it. The table gets copied over (albeit without any keys or indexes, which you then have to rebuild).&lt;br /&gt;&lt;br /&gt;This functionality is very much available through COM automation, and can therefore be used in a C# project. The problem is that the code is only available from within an Access module (although I’m sure one the readers will find a way to access this function directly from C#). So to get to it, you need to write a VB function that will import a table. The C# project will then need to load the Access database and execute the function which in turns performs the import.&lt;br /&gt;&lt;br /&gt;The only drawback to this method is that it is not asynchronous (although you could add threading on the C# side) and has no way to indicate progress.&lt;br /&gt;&lt;br /&gt;The VB function you’ll need to put into MS Access is quite simple, and basically calls the TransferDatabase method by passing it a DSN (pointing to the source database), a source table name and target table name. The code is as follows: &lt;/p&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;Public Function Import(dsnName As String, sourceTableName As String, targetTableName As String)&lt;br /&gt;‘ if the table already existsm, delete it.&lt;br /&gt;   On Error GoTo CopyTable&lt;br /&gt;   DoCmd.DeleteObject acTable, targetTableName&lt;br /&gt;CopyTable:&lt;br /&gt;   DoCmd.TransferDatabase _&lt;br /&gt;   acImport, _&lt;br /&gt;   &quot;ODBC Database&quot;, _&lt;br /&gt;   &quot;ODBC;DSN=&quot; + dsnName, _&lt;br /&gt;   acTable, _&lt;br /&gt;   sourceTableName, _&lt;br /&gt;   targetTableName&lt;br /&gt;End Function&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;color:#000000;&quot;&gt;And then the C# code: &lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;object accessObject = null;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;   accessObject = Activator.CreateInstance(Type.GetTypeFromProgID(&quot;Access.Application&quot;));&lt;br /&gt;&lt;br /&gt;   accessObject.GetType().InvokeMember(&lt;br /&gt;      &quot;OpenCurrentDatabase&quot;,&lt;br /&gt;      System.Reflection.BindingFlags.Default  System.Reflection.BindingFlags.InvokeMethod,&lt;br /&gt;      null,&lt;br /&gt;      accessObject,&lt;br /&gt;      new Object[] { &quot;AccessDbase.mdb&quot; });&lt;br /&gt;&lt;br /&gt;   accessObject.GetType().InvokeMember(&lt;br /&gt;      &quot;Run&quot;,&lt;br /&gt;      System.Reflection.BindingFlags.Default  System.Reflection.BindingFlags.InvokeMethod,&lt;br /&gt;      null,&lt;br /&gt;      accessObject,&lt;br /&gt;      new Object[] { &quot;Import&quot;, &quot;DSN Name&quot;, &quot;Source table name&quot;, &quot;Target table name&quot; });&lt;br /&gt;&lt;br /&gt;   accessObject.GetType().InvokeMember(&lt;br /&gt;      &quot;CloseCurrentDatabase&quot;,&lt;br /&gt;      System.Reflection.BindingFlags.Default  System.Reflection.BindingFlags.InvokeMethod,&lt;br /&gt;      null,&lt;br /&gt;      accessObject,&lt;br /&gt;      null);&lt;br /&gt;&lt;br /&gt;   MessageBox.Show(&quot;Copy succeeded.&quot;);&lt;br /&gt;}&lt;br /&gt;catch (Exception ex)&lt;br /&gt;{&lt;br /&gt;   string message = ex.Message;&lt;br /&gt;   while (ex.InnerException != null)&lt;br /&gt;   {&lt;br /&gt;      ex = ex.InnerException;&lt;br /&gt;      message += &quot;\r\n----\r\n&quot; + ex.Message;&lt;br /&gt;   }&lt;br /&gt;   MessageBox.Show(message);&lt;br /&gt;}&lt;br /&gt;finally&lt;br /&gt;{&lt;br /&gt;   if (accessObject != null)&lt;br /&gt;   {&lt;br /&gt;      System.Runtime.InteropServices.Marshal.ReleaseComObject(accessObject);&lt;br /&gt;      accessObject = null;&lt;br /&gt;   }&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;color:#000000;&quot;&gt;All we’re doing here is creating an instance of Access.Application, opening a database, executing the VB module to perform the import, closing the database and cleaning up.&lt;br /&gt;&lt;br /&gt;Note that for the copy to work, you need to specify several pieces of information:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The fully qualified name of the Access database &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The name of an ODBC DSN created in your control panel that points to the source database (i.e. where the table will be copied from) &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The name of the table as it appears in the source database &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color:#000000;&quot;&gt;The name you want to assign to the table once it’s been copied (can be the same as the source). &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;span style=&quot;color:#000000;&quot;&gt;Finally, it should be noted that the copy process creates the table with no keys or indexes, so these will have to be rebuilt after the copy is complete. This is very easily achieved, however, by executing SQL &quot;ALTER TABLE &quot; commands through ADO. There are plenty of articles out there that describe this so I won’t get into it here. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Credits and further info&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color:#000000;&quot;&gt;This article may not seem very big, but it is the culmination of a massive headache and lot of needle hunting (in a haystack of needles) on the net. I found several articles out there that helped out, and these are some of them:&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://www.thescripts.com/forum/thread255310.html&quot;&gt;http://www.thescripts.com/forum/thread255310.html&lt;/a&gt; - executing an MS Access module from C#&lt;br /&gt;&lt;a href=&quot;http://support.microsoft.com/kb/306683&quot;&gt;http://support.microsoft.com/kb/306683&lt;/a&gt; - executing MS Access modules from within C#. Note that the method described here uses early binding, which means you’re adding COM references to your project and you are therefore complicating your setup/installation package.&lt;br /&gt;&lt;a href=&quot;http://www.codeproject.com/cs/database/mdbcompact_latebind.asp&quot;&gt;http://www.codeproject.com/cs/database/mdbcompact_latebind.asp&lt;/a&gt; - very good article by Alexander Yumashev describing how to compact and repair an MS Access database from within C#. More importantly, it overcomes the problem in the Microsoft article mentioned above by using late binding.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;In conclusion&lt;/span&gt;&lt;br /&gt;MS Access is being put out to pasture out for many good reasons, but it’s still very much in use. So if you’re one of those people who still has to copy large amounts of data from another database source to MS Access, need to do in a C# project, and want a clean way to do it, then I think this article will help. If you don’t fall in that criteria, though, then I hope you at least had an interesting read and kept this in the back of your mind for future use.&lt;br /&gt;&lt;br /&gt;A sample project is available for testing here: &lt;a href=&quot;http://www.codeproject.com/useritems/MSAccessTableCopyInCSharp.asp&quot;&gt;http://www.codeproject.com/useritems/MSAccessTableCopyInCSharp.asp&lt;/a&gt; &lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/183614437741572348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/183614437741572348' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/183614437741572348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/183614437741572348'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/11/how-to-quickly-copy-tables-from-odbc.html' title='How to quickly copy tables from an ODBC source to MS Access within a C# project'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-8204612512095350226</id><published>2007-11-21T06:22:00.001-08:00</published><updated>2007-11-21T06:25:47.056-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fast data copy sql server ms access"/><title type='text'>A very fast table copy from SQL Server to MS Access</title><content type='html'>&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;New article coming up ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I&#39;ve recently fought (and won) a battle to get the fastest possible copy of a table from SQL Server to MS Access within a C# project. I tried the usual things like SSIS and ADO.net, but the fastest thing was the import utility within Access itself. I finally go it to work properly, and it flies (it&#39;s an average of 20 - yes 20 - times faster than copying through SSIS or other widely used methods). I&#39;ll post the article in the coming days.</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/8204612512095350226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/8204612512095350226' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/8204612512095350226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/8204612512095350226'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/11/very-fast-table-copy-from-sql-server-to.html' title='A very fast table copy from SQL Server to MS Access'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-1718422104276939497</id><published>2007-11-18T05:58:00.000-08:00</published><updated>2007-11-19T16:35:37.736-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="c#"/><category scheme="http://www.blogger.com/atom/ns#" term="central"/><category scheme="http://www.blogger.com/atom/ns#" term="logger"/><category scheme="http://www.blogger.com/atom/ns#" term="logging"/><category scheme="http://www.blogger.com/atom/ns#" term="observer"/><category scheme="http://www.blogger.com/atom/ns#" term="pattern"/><category scheme="http://www.blogger.com/atom/ns#" term="powerful"/><category scheme="http://www.blogger.com/atom/ns#" term="simple"/><category scheme="http://www.blogger.com/atom/ns#" term="singleton"/><title type='text'>A C# central logging mechanism using the Observer and Singleton patterns</title><content type='html'>&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Logging is something any respectable application needs to do. Whether it&#39;s to keep track of what the application is doing under the hood (for possible trouble shooting), to show a list of events that we might need to inform the user of, or simply to keep a history of events, logging is as necessary to the programming world as note taking is to a class room. If you don&#39;t do it, you might be able to get by for the moment. Just hope you never need to refer back to something that happened a few minutes, hours or days ago.&lt;br /&gt;&lt;br /&gt;This article shows an excellent mechanism for adding logging to a C# project. It is extremely powerful and versatile, yet very simple to implement and use. It uses two very common programming patterns: the singleton and the observer.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Background&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The ideas and code shown in here are not rocket science, so as long as you have at least a basic idea of object oriented programming, and have been playing around with C# for a while, I&#39;d say you&#39;re safe.&lt;br /&gt;&lt;br /&gt;This having been said, it is always a good idea to brush up on a couple of things if you want to get the most out of this. I would suggest reading up on patterns, and focusing on some of the more common ones such as the Singleton and Observer.&lt;br /&gt;&lt;br /&gt;To keep it brief and concise, however, I&#39;ll delve into these two for a bit and give you an idea of what they&#39;re about.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:#663333;&quot;&gt;&lt;span style=&quot;font-size:180%;&quot;&gt;The Singleton pattern&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;In layman&#39;s terms ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Probably the most widely known and one of simplest patterns, the singleton is a mechanism that ensures all objects in your process have access to a shared and single set of data and methods.&lt;br /&gt;Imagine an intersection where several roads meet, and where the cars need to ensure they do not crash into each other when crossing this intersection. Assuming there were no traffic lights to guide them, we would need a police officer standing in the middle to direct traffic. This officer would be a real life approximation of a singleton.&lt;br /&gt;&lt;br /&gt;The officer would receive visual queues from all roads, telling him which one is filling up the most with cars. With all this information, he would be able to decide which road to let the cars come through, and which roads to block.&lt;br /&gt;&lt;br /&gt;This would be significantly more complex if there were several officers controlling the intersection, where they would all be receiving visual queues from the roads, would have to communicate with each other and then collectively decide which road to let traffic come from.&lt;br /&gt;Similarly, a singleton object is something shared by all the objects in the system. For the purposes of the logging mechanism, the singleton is the one and only object to which all other objects will send the information they wish to have logged.&lt;br /&gt;&lt;br /&gt;Not only does this centralize and simplify control of the logging mechanism, this also gives the developer an excellent way to provide uniform formatting to the log output. You can add timestamps, titles, parameter information and more in just one place. None of the objects that need information to be logged need be concerned with this, as the singleton logger takes care of it on its own.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;Putting this in code ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When regular classes need to be used, they are instantiated as an object and then used. A singleton class, however, does not allow anyone except itself to instantiate it. This guarantees that only one copy of this object will ever run, and all objects in the program will be accessing this one copy.&lt;br /&gt;&lt;br /&gt;To accomplish this, the logger has only one private constructor and a private variable of its own type. The only way to really get a hold of this object from the outside then is to instantiate the Logger class and equate the new object to the static handle exposed in the class. The Instance property then checks to see if the private mLogger object was ever created, and if it was not, this is the only place where Logger will ever get instantiated.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;Logger&lt;br /&gt;{&lt;br /&gt;   private object mLock;&lt;br /&gt;   private static Logger mLogger = null;&lt;br /&gt;   // the public Instance property everyone uses to access the Logger&lt;br /&gt;   public static Logger Instance&lt;br /&gt;   {&lt;br /&gt;      get&lt;br /&gt;      {&lt;br /&gt;         // If this is the first time we&#39;re referring to the&lt;br /&gt;         // singleton object, the private variable will be null.&lt;br /&gt;         if (mLogger == null)&lt;br /&gt;         {&lt;br /&gt;            // for thread safety, lock an object when&lt;br /&gt;            // instantiating the new Logger object. This prevents&lt;br /&gt;            // other threads from performing the same block at the&lt;br /&gt;            // same time.&lt;br /&gt;            lock(mLock)&lt;br /&gt;            {&lt;br /&gt;               // Two or more threads might have found a null&lt;br /&gt;               // mLogger and are therefore trying to create a&lt;br /&gt;               // new one. One thread will get to lock first, and&lt;br /&gt;               // the other one will wait until mLock is released.&lt;br /&gt;               // Once the second thread can get through, mLogger&lt;br /&gt;               // will have already been instantiated by the first&lt;br /&gt;               // thread so test the variable again.&lt;br /&gt;               if (mLogger == null)&lt;br /&gt;               {&lt;br /&gt;                  mLogger = new Logger();&lt;br /&gt;               }&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;         return mLogger;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // the constructor. usually public, this time it is private to ensure&lt;br /&gt;   // no one except this class can use it.&lt;br /&gt;   private Logger()&lt;br /&gt;   {&lt;br /&gt;      mLock = new object();&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class SomeWorkerClass&lt;br /&gt;{&lt;br /&gt;   // any class wanting to use the Logger just has to create a&lt;br /&gt;   // Logger object by pointing it to the one and only Logger&lt;br /&gt;   // instance.&lt;br /&gt;   private Logger mLogger = Logger.Instance;&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;font-family:georgia;&quot;&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;The Observer pattern&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;In layman&#39;s terms again ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is where things get a bit more complex, but a bit more fun as well. The observer pattern is simply a mechanism where one object (such as our police officer from the example above) has the ability to dispatch a message to one or more observers. What they do with this message is completely up to them, and in fact, the officer doesn&#39;t even know who they are or what they do. He just knows how many observers there are, and has a predefined method for giving them this information.&lt;br /&gt;&lt;br /&gt;Going back to the traffic example: whenever the officer needs to let traffic on one road stop moving, he shows his open palm to that road&#39;s direction. He is in effect sending all traffic, which is observing him for input, a message. The traffic facing him will interpret this message and stop, and all other traffic will interpret the message and subsequently ignore it has no effect on them.&lt;br /&gt;&lt;br /&gt;Next, he waives to traffic in another road indicating that the drivers should start moving. Again, he has sent another message, and all the drivers will receive it in the same way, but act on it in different ways. Those facing him will start moving, and all others will simply ignore the message.&lt;br /&gt;So far, we have one observed subject (the officer) and several observers (the drivers). The beauty of this pattern, however, is that there could be observers of other types as well, and as long as they can receive the officer&#39;s messages in the same way as the drivers (i.e. as long as they have eye sight and are looking at him), they can act on the messages as well. A simple example would be for the officer to actually be a cadet on training, and a senior officer to be sitting in his car watching this cadet and taking notes of the stop and go messages. Again, the senior officer is observing the cadet and receiving his messages in the same way as the drivers, but is acting on them in a different manner.&lt;br /&gt;&lt;br /&gt;In programming terms, the officer would be sending his messages to the observers via an interface. If a given object implements an interface, any other object can interact with it through the properties and methods exposed in that interface without even knowing what the true nature of the object really is.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;color:#663333;&quot;&gt;Putting this in code as well ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first part of this pattern is the use of an interface which will allow the Logger to dispatch new log entries to the objects observing it. The beauty of this is that those objects could b of literally any type and offer all sorts of functionality. They could be forms, file writers, database writers, etc. But the Logger will only know that they implement this interface and will be able to communicate with them through it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;interface ILogger&lt;br /&gt;{&lt;br /&gt;   void ProcessLogMessage(string logMessage);&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;font-family:georgia;&quot;&gt;Next is the management of these observers within Logger. We need an array (or List&lt;&gt;) to store them (technically speaking, though, we&#39;re only storing a reference to them), and a public method by which they can be added to the array:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;class Logger&lt;br /&gt;{&lt;br /&gt;   private List&lt;ilogger&gt; mObservers;&lt;br /&gt;   private Logger()&lt;br /&gt;   {&lt;br /&gt;      mObservers = new List&lt;ilogger&gt;();&lt;br /&gt;   }&lt;br /&gt;   public void RegisterObserver(ILogger observer)&lt;br /&gt;   {&lt;br /&gt;      if (!mObservers.Contains(observer))&lt;br /&gt;      {&lt;br /&gt;         mObservers.Add (observer);&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;Whenever we want to implement a new observer, we just need to ensure it implements the ILogger interface and does something meaningful when the ProcessLogMessage method is executed. An example would be a FileLogger object that writes the log messages to a file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;class FileLogger: ILogger&lt;br /&gt;{&lt;br /&gt;   private string mFileName;&lt;br /&gt;   private StreamWriter mLogFile;&lt;br /&gt;   public string FileName&lt;br /&gt;   {&lt;br /&gt;      get&lt;br /&gt;      {&lt;br /&gt;         return mFileName;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   public FileLogger(string fileName)&lt;br /&gt;   {&lt;br /&gt;      mFileName = fileName;&lt;br /&gt;   }&lt;br /&gt;   public void Init()&lt;br /&gt;   {&lt;br /&gt;      mLogFile = new StreamWriter(mFileName);&lt;br /&gt;   }&lt;br /&gt;   public void Terminate()&lt;br /&gt;   {&lt;br /&gt;      mLogFile.Close();&lt;br /&gt;   }&lt;br /&gt;   public void ProcessLogMessage(string logMessage)&lt;br /&gt;   {&lt;br /&gt;      // FileLogger implements the ProcessLogMessage method by&lt;br /&gt;      // writing the incoming message to a file.&lt;br /&gt;      mLogFile.WriteLine(logMessage);&lt;br /&gt;   }&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;This class would then be instantiated and passed to Logger as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;public partial class Form1 : Form&lt;br /&gt;{&lt;br /&gt;   // the main Logger object private Logger mLogger;&lt;br /&gt;   // a logger observer that will write the log entries to a file&lt;br /&gt;   private FileLogger mFileLogger;&lt;br /&gt;   private void Form1_Load(object sender, EventArgs e)&lt;br /&gt;   {&lt;br /&gt;      // instantiate the logger&lt;br /&gt;      mLogger = Logger.Instance;&lt;br /&gt;      // instantiate the log observer that will write to disk&lt;br /&gt;      mFileLogger = new FileLogger(@&quot;c:\temp\log.txt&quot; );&lt;br /&gt;      mFileLogger.Init();&lt;br /&gt;      // Register mFileLogger as a Logger&lt;br /&gt;      observer. mLogger.RegisterObserver(mFileLogger);&lt;br /&gt;   }&lt;br /&gt;   private void Form1_FormClosing(object sender, FormClosingEventArgs e)&lt;br /&gt;   {&lt;br /&gt;      // The application is shutting down, so ensure the file&lt;br /&gt;      // logger closes the file it&#39;s been writing to.&lt;br /&gt;      mFileLogger.Terminate();&lt;br /&gt;   }&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Putting the patterns together&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Our logger will use both of these patterns, and the attached sample code uses two observers: the FileLogger mentioned above, and the actual form itself. The FileLogger logs the messages to a file, and the form shows the messages in a textbox control. This is obviously a simple implementation, but it could be used for much more creative purposes. We could have an observer that writes the log entries to a database table, another that concatenates all the entries and the emails the log, etc.&lt;br /&gt;&lt;br /&gt;Whenever the form needs to have something logged, it simply executes the AddLogMessage() on the logger and passes it the log entry:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;class Logger&lt;br /&gt;{&lt;br /&gt;   public void AddLogMessage(string message)&lt;br /&gt;   {&lt;br /&gt;      // Apply some basic formatting like the current timestamp&lt;br /&gt;      string formattedMessage = string.Format(&quot;{0} - {1}&quot;, DateTime.Now.ToString(), message);&lt;br /&gt;      foreach (ILogger observer in mObservers)&lt;br /&gt;      {&lt;br /&gt;         observer.ProcessLogMessage(formattedMessage);&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;public partial class Form1 : Form&lt;br /&gt;{&lt;br /&gt;   private void button1_Click(object sender, EventArgs e)&lt;br /&gt;   {&lt;br /&gt;      mLogger.AddLogMessage(&quot;The button was clicked.&quot;);&lt;br /&gt;   }&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;Using the code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The sample project does not perform any complex operations, but showcases the logging discussed in this article. The main form has a button that, when clicked, increments a private counter and displays the value in a text box.&lt;br /&gt;&lt;br /&gt;Every time the counter is increased, however, the logger is informed. In turn, the logger formats the message it receives and dispatches it to all the observers for processing.&lt;br /&gt;&lt;br /&gt;As a nice plus, the Logger&#39;s AddLogMessage() method is overwritten to accept an exception. If the application throws an exception and we want it properly logged, we just pass the exception to the Logger and it extracts all the messages from the exception and inner exceptions (if applicable), puts them together, adds the stack trace, and then logs the whole thing. Very useful.&lt;br /&gt;&lt;span style=&quot;font-size:180%;color:#663333;&quot;&gt;In conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I hope this article and attached sample prove useful. If you have any suggestions for improvement I&#39;m all ears, so post a message and let us know what you think!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A sample project is available for testing here: &lt;a href=&quot;http://www.codeproject.com/useritems/ObserverLogging.asp&quot;&gt;http://www.codeproject.com/useritems/ObserverLogging.asp&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/1718422104276939497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/1718422104276939497' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/1718422104276939497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/1718422104276939497'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/11/c-central-logging-mechanism-using.html' title='A C# central logging mechanism using the Observer and Singleton patterns'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3377869834318369205.post-3911334476425890130</id><published>2007-11-18T05:37:00.000-08:00</published><updated>2007-12-25T12:27:40.366-08:00</updated><title type='text'>So I&#39;m joining the crowds and blogging...</title><content type='html'>&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_louS6gBvhAKa8up79YYn-CLIQ5G255HK2hnViUQsKl-n1N7eHL7c5SLtpTdOOtSWzBi_3P2CuZuyjqLG9I3QVfFdDhNTA8kBXWstskrHRthyfKd-zYHMenfTaUb0hvZjeiOEaXyaeJkW/s1600-h/Atreides+coat+of+arms+-+transparent+background.jpg&quot;&gt;&lt;img style=&quot;float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_louS6gBvhAKa8up79YYn-CLIQ5G255HK2hnViUQsKl-n1N7eHL7c5SLtpTdOOtSWzBi_3P2CuZuyjqLG9I3QVfFdDhNTA8kBXWstskrHRthyfKd-zYHMenfTaUb0hvZjeiOEaXyaeJkW/s400/Atreides+coat+of+arms+-+transparent+background.jpg&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5148009856626658578&quot; /&gt;&lt;/a&gt;Never thought I&#39;d be one to just follow the crowds, but I guess some things just make sense. Blogging sounds like an easy way to write and reach the masses easily, so here I am, doing just that.&lt;br /&gt;&lt;br /&gt;Anyway, most of my entries will be programming-oriented. I do a lot of research on the net to figure out how to solve complex issues, and once I have it all working, I sometimes write it up in an easy to read article that attempts to spare the reader from the pain and hard work involved in doing all the research. I know I&#39;d like to find more articles like this, so I&#39;m sure there are others like me out there.&lt;br /&gt;&lt;br /&gt;So here goes. I&#39;ll be posting my first article really soon.</content><link rel='replies' type='application/atom+xml' href='http://cookingwithcsharp.blogspot.com/feeds/3911334476425890130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3377869834318369205/3911334476425890130' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/3911334476425890130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3377869834318369205/posts/default/3911334476425890130'/><link rel='alternate' type='text/html' href='http://cookingwithcsharp.blogspot.com/2007/11/so-im-joining-crowds-and-blogging.html' title='So I&#39;m joining the crowds and blogging...'/><author><name>Muaddubby</name><uri>http://www.blogger.com/profile/11190434513081782436</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgALd_Mu8kuYJYB6RMxZP-dGqa3QdDcPHdg08IzBxsn8cvX79pfuPBk0533MAkQ7so772NlisJnBbKpLuUxq0HrVg6i8p2ep34_LUja7L1rVEYFJ2CdPwHGbzzmUAL-6Ys/s200/Atreides_Crest_resized.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_louS6gBvhAKa8up79YYn-CLIQ5G255HK2hnViUQsKl-n1N7eHL7c5SLtpTdOOtSWzBi_3P2CuZuyjqLG9I3QVfFdDhNTA8kBXWstskrHRthyfKd-zYHMenfTaUb0hvZjeiOEaXyaeJkW/s72-c/Atreides+coat+of+arms+-+transparent+background.jpg" height="72" width="72"/><thr:total>0</thr:total></entry></feed>