Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Monday, November 14, 2016

Exceptions and Performance

First, let me put out this disclaimer - the tests and improvements shown here are a worst case scenario done with "out of bounds" testing.  While the tests and solutions here show 4,000x+ performance improvement, this is not a typical real world scenario.  The information learned here, though, can help gain significant performance improvements in most typical applications.  Don't expect the results shown here in a normal real world application as there are normally a lot of other factors affecting performance other than just one or two pain points.

In a prior post, I discussed the issues with string equality and how to easily increase performance around those areas.  Recently I ran into another problematic problem that seems to plague code - the exception.

Exceptions, in languages such as .Net and Java, are there to let the code know when something has happened the code has not accounted for.  This could be something such as an attempt to divide by 0, a file missing, or even a network/database connection lost.  Exceptions are good things - they allow the programmer to work around the problem.  For instance, with a database connection is lost and an exception happens, the program could attempt to reconnect when it receives the exception.  Of course, there's an exception to this, there are some exceptions that can't easily be handled in user code, such as out of stack space or out of memory - most languages simply abort the program at the point of these exceptions as it's normally a sign something seriously went wrong.  But, exceptions are generally meant to be handled and accounted for, or, if at all possible, avoided entirely as they're extremely slow.

How slow?  Here's a comparison of various loops against an exception.  For the tests, the tests are executed 5 times with an inner loop that performs a simple calculation 250,000,000 times - yes, I did say 250 million.  I used 250 million as the loop count as I'm trying to get to get a baseline of approximately 1 second for the specific tests.

First, though, a walk-thru of the performance test code.

    int iterations = 5;
    int loopCount = 250000000;
    Stopwatch sw = new Stopwatch();
    int sum = 0;
    for (int k = 0; k < iterations; k++)
    {
        sw.Start();
        for (int j = 0; j < loopCount; j++)
        {
            //code to test goes here
        }
        sw.Stop();

        System.Console.Write(sw.ElapsedMilliseconds + " ");
        sw.Reset();
    }
    System.Console.WriteLine();

In general, there's nothing really special about this code.  It sets up the variables, creates a stopwatch timer (more on that in a second), and then does the loops, with the stopwatch being stopped and reset at the end.  The only interesting thing here is the stopwatch timer.

Date/time calculations, such as those done with DateTime.Now.Millisecond, are notorious for not being very accurate - they can vary and are often off by as much as 100ms (on top of DateTime.Now being fairly slow itself).  The calculations we need here need to be more accurate.  The Stopwatch timer, which is in the System.Diagnostics namespace, is normally very accurate and often to as low as 1ms.  Hence, the stopwatch timer is used here for that reason.

Now, back to the timings.

The simplest case is an empty loop that does nothing.  The results, for an empty loop, are around 754ms to do the entire loop 250 million times.  The exact times I received were:

785 742 769 748 727

Next, let's see what affect a simple calculation will have on this timing.  To help prevent the compiler from possibly optimizing the calculation away, we'll put a variable named sum (shown above) on the outside of the loop and print out the calculation of the summation of j*k, through the entire loop, at the end of the loops.  Here's the code for this simple calculation.

    sum = 0;
    for (int k = 0; k < iterations; k++)
    {
        sw.Start();
        for (int j = 0; j < loopCount; j++)
        {
            sum = sum + j * k;
        }
        sw.Stop();

        System.Console.Write(sw.ElapsedMilliseconds + " ");
        sw.Reset();
    }
    System.Console.WriteLine();

The results for this one, as we'd expect, are slightly higher than the loop with no code - average of around 938ms (so we come very close to the 1-second test I intended).  The exact results were:

959 927 911 942 953

Ok, now let's see what affect a conditional has on this - we'll check to see if j (inner loop) is 0, if so, just add k (outer loop) to sum, otherwise do the j*k calculation.  The code –

    sum = 0;
    for (int k = 0; k < iterations; k++)
    {
        sw.Start();
        for (int j = 0; j < loopCount; j++)
        {
            if (j == 0)
            {
                sum = sum + k;
            }
            else
            {
                sum = sum + j * k;
            }
        }
        sw.Stop();

        System.Console.Write(sw.ElapsedMilliseconds + " ");
        sw.Reset();
    }
    System.Console.WriteLine();

For this one, we have roughly 1324ms of time used for this summation. Almost double the empty loop and a little over 300ms than the prior example.  Still, 1.3s for 250 million calculations isn't bad.

Since we're on the topic of conditionals, can we get better speed out of the C# conditional operator (?:)?  The code technically should be roughly equivalent to the code above when it converts to IL.  So, for this code:

    sum = 0;
    for (int k = 0; k < iterations; k++)
    {
        sw.Start();
        for (int j = 0; j < loopCount; j++)
        {
            sum = sum + ((j == 0) ? k : j * k);
        }
        sw.Stop();

        System.Console.Write(sw.ElapsedMilliseconds + " ");
        sw.Reset();
    }
    System.Console.WriteLine();

The results are a bit surprising:

2308 2245 2286 2274 2317

Wait! What? Why? Why is the code above twice as slow as the "equivalent" inline code? Good question but that's one to investigate at a different time since the goal of this comparison is exceptions. The hint on this, though, is to look at the IL that's generated between the two conditional methods. [but, oh, you thought that using the newest way of doing things makes it better and more condensed? Uh, nope - can't assume anything like that - using this is almost twice as slow as the verbose code in these circumstances].

Ok, so now we have our baseline, some simple code, and two ways of doing conditions. Now, to the meat of the matter - how bad is the exception? Let's try with throwing an exception within a try/catch block. The catch block does nothing mainly for the sake of trying to get accurate timing of the performance test.

    sum=0;
    for (int k = 0; k < iterations; k++)
    {
        sw.Start();
        for (int j = 0; j < loopCount/2000000; j++)
        {
            try
            {
                throw new Exception();
            }
            catch(Exception)
            {

            }
        }
        sw.Stop();

        System.Console.Write(sw.ElapsedMilliseconds + " ");
        sw.Reset();
    }
    System.Console.WriteLine();

The results average out to be 1382ms - oh, so just slightly above the one for the conditional then, right?  So, why am I even writing this blog to complain about something that's not a problem?  Well, look closely at the inner loop - look at the count - loopCount (250 million) DIVIDED BY 2,000,000...yes, a for loop that counts from 0 up to 250,000,000/2,000,000, which means it counts up to 125!  Yes, 125...not 100,000, just 125...so 1382ms average for just 125 exceptions!  That's roughly 10ms each exception!  Nah, exceptions aren't really a problem, they're a disaster!  The exact times I received for this run were:

1801 1269 1248 1245 1351

And, yes, 1801 seems a bit of an outlier but really it's right in line with the others at taking 14ms vs 10ms.  Either way, it's over 1 second for just 125 exceptions.

Now, I'm doing these tests in debug mode and with any CPU as the configuration.  I'm also running these tests within the IDE and with Intelitrace off (Intelitrace only makes things worse, with the worst hit coming to the exceptions test - up to a 3x further performance drop).  So, can we get better results when run in x86, x64 or in release modes?  Well, let's try:

Debug - x86
***Empty loop***
803 844 770 767 769
***Simple calculation***
901 900 899 903 905
***If conditional with simple calculation***
1248 1241 1241 1234 1234
***Conditional operator with simple calculation***
2215 2185 2196 2207 2206
***Exceptions (scaled down by 2,000,000)***
1100 1075 1070 1101 1086

Debug - x64
***Empty loop***
845 844 818 802 818
***Simple calculation***
1021 1021 1014 1023 1008
***If conditional with simple calculation***
1315 1320 1364 1371 1364
***Conditional operator with simple calculation***
2247 2204 2189 2211 2208
***Exceptions (scaled down by 2,000,000)***
2760 2922 2785 2807 2793

Release - Any CPU
***Empty loop***
136 145 138 131 132
***Simple calculation***
131 132 134 134 150
***If conditional with simple calculation***
277 266 270 271 271
***Conditional operator with simple calculation***
496 515 495 504 495
***Exceptions (scaled down by 2,000,000)***
758 793 762 816 872

Release - x86
***Empty loop***
134 142 146 134 150
***Simple calculation***
135 131 133 145 148
***If conditional with simple calculation***
267 272 258 269 260
***Conditional operator with simple calculation***
500 501 503 500 525
***Exceptions (scaled down by 2,000,000)***
794 781 816 811 763

Release - x64
***Empty loop***
240 224 208 204 203
***Simple calculation***
235 237 227 222 225
***If conditional with simple calculation***
336 332 331 334 339
***Conditional operator with simple calculation***
341 360 380 357 356
***Exceptions (scaled down by 2,000,000)***
1885 1883 1988 1973 2031

Ok, so, in general, if we're doing release mode and x86, we can get it down quite well, to roughly 6x slower than a simple calculation.  Worst case performance seems to be on the x64 with almost a 9x performance drop compared to a simple calculation.  Now, remember, the exceptions are actually only executing the loop 125 times compared to 250,000,000 for the others, so, in reality, we're talking 6x * 2,000,000 or 12 million times worse for the best case and 9x * 2,000,000 or 18 million times for the worst case. Are you having a performance issue in your application, you're debugging it in the IDE, and the app is throwing a lot of exceptions, and you're wondering why the app is so slow?  Well, to quote a famous Myth Buster - "There's your problem!"  

So, in the "real world," apps are not run in the IDE - they're started by the OS in various ways (ie command prompt, service/daemon, etc).  What affect does the IDE have on exceptions?  Well, let's see...same tests, same code:

Debug - x86
***Empty loop***
752 748 746 759 758
***Simple calculation***
887 890 895 890 883
***If conditional with simple calculation***
1213 1209 1202 1205 1186
***Conditional operator with simple calculation***
2162 2241 2164 2155 2162
***Exceptions (scaled down by 2,000,000)***
2 2 2 2 2

2ms for exceptions now?  The entire loop ran in 2ms?  The fun part here is 2ms for just 125 executions of the loop.  Let's drop the scale down a bit and see how it does.  For the following runs, I've set the scale to be 4,000, so the exceptions loop runs basically 62,500 times and we get the following results for each of the various build configurations.  Remember this is outside the IDE (or also via Ctrl-F5 within the IDE).

Debug - x86
***Empty loop***
768 758 771 764 752
***Simple calculation***
888 901 891 889 890
***If conditional with simple calculation***
1216 1219 1254 1233 1227
***Conditional operator with simple calculation***
2162 2173 2157 2157 2170
***Exceptions (scaled down by 4,000)***
1287 1311 1352 1292 1479

Debug - x64
***Empty loop***
820 803 834 793 791
***Simple calculation***
1010 1018 1026 1014 1042
***If conditional with simple calculation***
1413 1290 1295 1315 1293
***Conditional operator with simple calculation***
2237 2235 2270 2314 2277
***Exceptions (scaled down by 4,000)***
948 949 1011 996 990

Release - x86
***Empty loop***
139 133 135 131 134
***Simple calculation***
131 131 130 135 132
***If conditional with simple calculation***
261 260 263 266 263
***Conditional operator with simple calculation***
504 519 503 514 513
***Exceptions (scaled down by 4,000)***
1407 1392 1446 1407 1358

Release - x64
***Empty loop***
133 141 134 133 152
***Simple calculation***
600 602 596 599 604
***If conditional with simple calculation***
597 603 607 612 592
***Conditional operator with simple calculation***
599 599 591 599 587
***Exceptions (scaled down by 4,000)***
885 901 883 855 931

So, about 500x faster outside the IDE (125x500=62,500).  Still, though, at best case we're talking roughly 4,000x slower than the simple calculation itself...  Still, a large enough difference to be a fairly major problem when exceptions are being thrown a lot.

Am I saying we should abandon exceptions?  No, not at all (sure, abandon them and go back to what - the "on error gosub" of the VB era?).  I am saying that we should use them for what they're there for - they were designed to give details about a problem that the code did not account for.  They should not be used for control flow to break out of methods nor should they be "allowed" to happen "on their own" without code trying to find and avoid the problem first.  The simple answer is exceptions are expensive - guard against them to keep them from happening in the first place, where it is possible and where it makes sense.  If the code expects a file to exist, verify the file exists before you try to do something with it - don't assume that because you checked for the file 30 seconds prior that it still exists.  Do the checks and guards where it makes sense in the code.  If exceptions are extremely rare and should "never" happen, the guard does still cost so use judgment there, but, for things that are possible to happen, definitely try to guard against them to prevent the cost of the exception hit.

Just as an example, let's try a similar test to above but with a guaranteed failure for a certain percentage of the test.  We'll do a 0-100% fail rate (for space, the results for only 0-10% will be shown) over a smaller loop count of 2,500,000.  The code to do the test and avoid the division by zero exception looks like:

int sum = 0;
System.Console.WriteLine("***J/K summation***");
for (int l = 0; l < 101; l+=1)
{
    double remainderValue = loopCount * (1.0 - l / 100.0);
    double avg = 0.0;
    sum = 0;
    
    for (int k = 0; k < iterations; k++)
    {
        sw.Start();
        for (int j = 0; j < loopCount; j++)
        {
            if (remainderValue < 0 && (int)remainderValue >j)
            {
                sum = sum + k * j / Math.Max(0, 
                   (int)remainderValue - j);
            }
            else
            {
                sum = sum + k;
            }
        }
        sw.Stop();

        avg = avg + sw.ElapsedMilliseconds;
        sw.Reset();
    }
    System.Console.Write("  " + (int)(avg / iterations) +
        " (" + l + "%) ");
}
System.Console.WriteLine();

And the code that allows the exceptions to happen looks like:

System.Console.WriteLine("***J/K summation w/ exceptions***");
for (int l = 0; l < 101; l += 1)
{
    double remainderValue = loopCount * (1.0 - l / 100.0);
    double avg = 0.0;
    sum = 0;

    for (int k = 0; k < iterations; k++)
    {
        sw.Start();
        for (int j = 0; j < loopCount; j++)
        {
            try
            {
                sum = sum + k * j / Math.Max(0, 
                    (int)remainderValue - j);
            }
            catch (DivideByZeroException)
            {
                sum = sum + k;
            }
        }
        sw.Stop();

        avg = avg + sw.ElapsedMilliseconds;
        sw.Reset();

    }
    System.Console.Write("  " + (int)(avg / iterations) + 
        " (" + l + "%) ");
}
System.Console.WriteLine();

The results, not performed in the IDE, for the first 10% without exceptions looks like:

***J/K summation***
  26 (0%)   27 (1%)   25 (2%)   23 (3%)   25 (4%)   24 (5%)
  25 (6%)   23 (7%)   32 (8%)   29 (9%)   32 (10%)

And with exceptions, also, not in the IDE, the timing looks like:

***J/K summation w/ exceptions***
    28 (0%)  617 (1%) 1227 (2%) 1826 (3%) 2292 (4%)  2708 (5%)
  3260 (6%) 3787 (7%) 4154 (8%) 5126 (9%) 5412 (10%)

So, at even 1% of the data failing (25,000 items out of 2,500,000), we're seeing roughly a 30x drop in performance and at 10% fail rate (250,000 items) we're seeing over 150x drop in performance - and this drop is already above the "slower performing" code that has the guard clauses in it to prevent the exceptions.

Hopefully, this makes the point fairly clear - exceptions are expensive, even when compared to adding in guard clauses to help prevent them.  Even a small frequency of exceptions can cause substantial performance problems in an application so prevent them when you can.  

Saturday, July 16, 2011

Factories in C#-Basic, Cached, and Dynamic

Introduction

It seems that one of the more common operations in modern object orientated languages is creating new objects.  In most languages, this is accomplished by using the “new” operator…this is nothing new for most of us out there who’ve been doing OO programming for any length of time.  For those who haven’t been, here’s the general idea – we have a class we want to create and use (let’s say a “Dog”) in our main program.  Here’s the Dog class:

Dog.cs
  1. public class Dog
  2. {
  3.     protected string AnimalType { get; private set; }
  4.  
  5.     public Dog()
  6.     {
  7.         AnimalType="Dog";
  8.     }
  9.  
  10.     public void IntroduceSelf()
  11.     {
  12.         System.Console.WriteLine(IntroductionLine);
  13.         System.Console.WriteLine(Speak);
  14.         System.Console.WriteLine();
  15.     }
  16.  
  17.     protected string IntroductionLine
  18.     {
  19.         get
  20.         {
  21.             string introLine = "Hello, I am a " + AnimalType;
  22.             return introLine;
  23.         }
  24.     }
  25.  
  26.     protected string Speak
  27.     {
  28.         get
  29.         {
  30.             return "Woof";
  31.         }
  32.     }
  33. }

And to create a new Dog we do this in our main program:

Program.cs
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         Dog dog = new Dog();
  6.         dog.IntroduceSelf();
  7.  
  8.         System.Console.WriteLine("Press <enter> to end");
  9.         Console.ReadLine();
  10.     }
  11. }

Ok, simple enough, right?

Well, let’s say the requirements expand and we now need to create a cat and a dog.  [ok, now, you ol fogies – I know you already know this…just skim down if you’re bored].  So, we create a new class named Cat that does pretty much the same thing as the Dog class did, with obvious exceptions.  [At this point, if you’re an OO programmer, alarm bells should be going off in your head – Cat class does pretty much the same thing as the Dog class].

So, here’s the Cat class -

Cat.cs
  1. public class Cat
  2.     {
  3.         protected string AnimalType { get; private set; }
  4.  
  5.         public Cat()
  6.         {
  7.             AnimalType = "Cat";
  8.         }
  9.  
  10.         public void IntroduceSelf()
  11.         {
  12.             System.Console.WriteLine(IntroductionLine);
  13.             System.Console.WriteLine(Speak);
  14.             System.Console.WriteLine();
  15.         }
  16.  
  17.         protected string IntroductionLine
  18.         {
  19.             get
  20.             {
  21.                 string introLine = "Hello, I am a " + AnimalType;
  22.                 return introLine;
  23.             }
  24.         }
  25.  
  26.         protected string Speak
  27.         {
  28.             get
  29.             {
  30.                 return "Meow";
  31.             }
  32.         }
  33.     }

And our main program to create a dog and cat looks like this:

Program.cs
  1. class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             Dog dog = new Dog();
  6.             dog.IntroduceSelf();
  7.  
  8.             Cat cat = new Cat();
  9.             cat.IntroduceSelf();
  10.  
  11.             System.Console.WriteLine("Press <enter> to end");
  12.             Console.ReadLine();
  13.         }
  14.     }

Ok, not bad…and we solved the requirements…but, look at all that duplicated code…what if the requirements change again (and, believe me, they will)?  What if we added 50 animal types and then we found a bug that was common in all that code…50 classes would have to change to fix that bug.  What’s the answer?  Using the OO concept of inheritance.

Brief Overview of Inheritance (as it pertains to Factories)

One of the key features of inheritance is the ability to reuse code from a class higher up the inheritance chain (such as a parent or grandparent [or from a base class in C# terms]).  This reused code can be in the form of functions/procedures, data members, or properties (I’m specifically referring to class inheritance here, not inheritance via interfaces).  So, what does this have to do with factories and creation of objects – inheritance is a prerequisite to getting a factory to work for object creation.  So, let’s go ahead and use inheritance and get rid of some of this duplicated code…and, while we’re at it, let’s create a new animal class for a pig.

We’ll start with an abstract base class.  We really don’t want to be creating an animal by itself and there are some things the animals themselves will know how to do that this base animal class won’t (i.e. how to speak).

AbstractAnimalBase.cs
  1. public abstract class AbstractAnimalBase
  2.     {
  3.         protected string AnimalType { get; private set; }
  4.  
  5.         public AbstractAnimalBase(string type)
  6.         {
  7.             AnimalType = type;
  8.         }
  9.  
  10.         public void IntroduceSelf()
  11.         {
  12.             System.Console.WriteLine(IntroductionLine);
  13.             System.Console.WriteLine(Speak);
  14.             System.Console.WriteLine();
  15.         }
  16.  
  17.         protected virtual string IntroductionLine
  18.         {
  19.             get
  20.             {
  21.                 string introLine = "Hello, I am a " + AnimalType;
  22.                 return introLine;
  23.             }
  24.         }
  25.  
  26.         protected abstract string Speak
  27.         {
  28.             get;
  29.         }
  30.     }

Ok, now for the dog, cat, and pig classes that will use this base class.  Take a look at how much shorter these are than the original version that didn’t use inheritance.

Dog.cs
  1. public class Dog : AbstractAnimalBase
  2.     {
  3.         public Dog()
  4.             : base("Dog")
  5.         {
  6.         }
  7.  
  8.         protected override string Speak
  9.         {
  10.             get { return "Woof"; }
  11.         }
  12.     }

 

Cat.cs
  1. public class Cat : AbstractAnimalBase
  2.     {
  3.         public Cat()
  4.             : base("Cat")
  5.         {
  6.         }
  7.  
  8.         protected override string Speak
  9.         {
  10.             get { return "Meow"; }
  11.         }
  12.     }

 

Pig.cs
  1. public class Pig : AbstractAnimalBase
  2.     {
  3.         public Pig()
  4.             : base("Pig")
  5.         {
  6.         }
  7.  
  8.         protected override string Speak
  9.         {
  10.             get { return "Oink"; }
  11.         }
  12.     }

Ok, now to the meat of this post.

Introduction to Factories

So, what is a factory anyway and what can it do for us?  In layman terms, a factory is a piece of code that returns back a specific object from a given input.  Ok, so what’s so special about that, right? – new does that for me.  That’s correct, but, what if you don’t know what type of object you want while you’re coding?  That’s where the factory comes in – you tell the factory what type of object you want and it will return the object needed for that type to you.  In more programmer speak, a factory is one of the Gang of Four design patterns that is used to create objects without having to specify the exact class that will be created.

Yes, I know, you’re the programmer and you will always know what object you need and when - will you though?  Let’s say you’re reading a config file and wanting to do certain operations or load certain values based on the config – do you always know what and how it will be configured?  Or, let’s say you’re reading a database and you’ll have to load data from different tables depending on what the value of a specific field is…or, you’re looking at the file system for images and you come across a JPG and the next image is a GIF.  Each of these is a good candidate for a factory.

Typically, a factory is a static class and/or a static method.  Having the factory class static allows access to it without having to create an instance of the factory class.

Basic Factories

Factories using Strings

The factory method will generally return the common base class or common interface of the objects that could be created by the method…normally the structure is simple, either in a if-else or in a switch statement.  So, for the animal factory, we’d have something like the following code:

AnimalFactory.cs
  1. public static class AnimalFactory
  2.     {
  3.         public static AbstractAnimalBase CreateAnimal(string type)
  4.         {
  5.             type = type.ToLower().Trim();
  6.             switch (type)
  7.             {
  8.                 case "dog":
  9.                     return new Dog();
  10.                 case "cat":
  11.                     return new Cat();
  12.                 case "pig":
  13.                     return new Pig();
  14.                 default:
  15.                     throw new Exception(String.Format("Unknown animal type {0}", type));
  16.             }
  17.         }
  18.     }

Factories using Enumerations

A complaint with the above code is that it’s using strings to do the matching, which some claim is inefficient (due partly to the to lower and trim calls) and error prone (if you misspell, it’ll fail).  This can easily be changed to use an enumeration, which will gain some speed (no need for string manipulation) and is less error prone but adds a little bit more maintenance to the code – the programmer has to update the enum as well as the factory code.  Here’s the same code but using an enumeration instead:

AnimalFactory.cs
  1. public static class AnimalFactory
  2.     {
  3.         public enum AnimalEnum
  4.         {
  5.             Dog,
  6.             Cat,
  7.             Pig
  8.         };
  9.  
  10.         public static AbstractAnimalBase CreateAnimal(AnimalEnum type)
  11.         {
  12.             switch (type)
  13.             {
  14.                 case AnimalEnum.Dog :
  15.                     return new Dog();
  16.                 case AnimalEnum.Cat:
  17.                     return new Cat();
  18.                 case AnimalEnum.Pig:
  19.                     return new Pig();
  20.                 default:
  21.                     throw new Exception(String.Format("Unknown animal type {0}", type));
  22.             }
  23.         }
  24.     }

Well, that’s it for the factory, right?  Well, in the general case, yes…but, there are a couple specific instances that I’ve found a use for lately that someone else may be interested in.

Cached Factories

There are times when creating a class is a long running process and you want to cache this data so you don’t kill your performance, but, the classes that do this all inherit from a base class so they are candidates for a factory pattern.  The sample factories above would create a new animal each time that type is requested – which could run a long-running process.  The cached factory helps with this situation…one thing to note with the cached factory it will return back the same object instance for a specific given type (not that this isn’t necessarily a singleton instance of a class).  So, for example, using the animal example above, the program requests a dog for the first time, a dog (#1) is created and returned back to the caller…on the second call to get a dog, dog (#1) is still returned to the caller…let’s say the code is slightly different than above and we return back a dog for an input of “mut”…with this situation, the program passes in “mut” and we get back a different instance of a dog (#2).  So, don’t get cached returns confused with singletons.

Now, for the code for a cached factory.  Pretty similar to the others but it uses a dictionary to keep hold the type and the returned value.  The code could easily be expanded to allow removal of cached values, etc, if needed.

AnimalFactory.cs
  1. using System.Collections.Generic;
  2.     public static class AnimalFactory
  3.     {
  4.         private static Dictionary<string, AbstractAnimalBase> AnimalCache { get; set; }
  5.  
  6.         public static AbstractAnimalBase CreateAnimalCached(string type)
  7.         {
  8.             if (AnimalCache == null)
  9.             {
  10.                 AnimalCache = new Dictionary<string, AbstractAnimalBase>();
  11.             }
  12.  
  13.             type = type.ToLower().Trim();
  14.  
  15.             if (!AnimalCache.ContainsKey(type))
  16.             {
  17.                 AbstractAnimalBase animal;
  18.                 switch (type)
  19.                 {
  20.                     case "dog":
  21.                         animal = new Dog();
  22.                         break;
  23.                     case "cat":
  24.                         animal = new Cat();
  25.                         break;
  26.                     case "pig":
  27.                         animal = new Pig();
  28.                         break;
  29.                     default:
  30.                         throw new Exception(String.Format("Unknown animal type {0}", type));
  31.                 }
  32.                 AnimalCache.Add(type,animal);
  33.             }
  34.             return AnimalCache[type];
  35.         }
  36.     }

Alternate “Factory” (Cache)

An alternate version of the above factory eliminates the switch statement – so, each animal object will be created and cached…but, each object must manually be created outside the factory (hmm, kinda longer a factory if the object is created elsewhere, is it?) – but that add could be technically done from anywhere, according to the permission of the function/class.  So, the main method could add to the factory and other classes within the application use the factory with what was loaded from main.

AnimalFactory.cs
  1. using System.Collections.Generic;
  2.     public static class AnimalFactory
  3.     {
  4.         private static Dictionary<string, AbstractAnimalBase> AnimalCache { get; set; }
  5.  
  6.         internal void AddAnimalToCache(string type, AbstractAnimalBase animal)
  7.         {
  8.             if (AnimalCache == null)
  9.             {
  10.                 AnimalCache = new Dictionary<string, AbstractAnimalBase>();
  11.             }
  12.  
  13.             type = type.ToLower().Trim();
  14.  
  15.             if (!AnimalCache.ContainsKey(type))
  16.             {
  17.                 AnimalCache.Add(type, animal);
  18.             }
  19.             else
  20.             {
  21.                 throw new Exception(String.Format("Animal type {0} already exists", type));
  22.             }
  23.         }
  24.  
  25.         public static AbstractAnimalBase GetAnimalFromCache(string type)
  26.         {
  27.             if (AnimalCache == null)
  28.             {
  29.                 AnimalCache = new Dictionary<string, AbstractAnimalBase>();
  30.             }
  31.  
  32.             type = type.ToLower().Trim();
  33.  
  34.             if (!AnimalCache.ContainsKey(type))
  35.             {
  36.                 throw new Exception(String.Format("Unknown animal type {0}", type));
  37.             }
  38.  
  39.             return AnimalCache[type];
  40.         }
  41.     }

Dynamic Factories

One thing that has always bothered me about the factory is having to add a class for what I want and then having to also modify the factory and maybe even an enum.  There has to be a way for classes to “self register” themselves with a factory…well, there is with the above code – the constructor of each subclassed animal can add itself to the factory.  Well, that’s great…but who is going to call the constructor for each of those sub-classes?  Too bad the base class can’t determine it’s subclasses…or, wait, it can, but indirectly – through reflection.

Couple words on reflection and creating a factory in this way – reflection is “slow” in general, so you’ll probably want to cache the objects that are created and you probably only want to discover your classes once – on start up or on first use of the factory.  Also, with this method, I’ve only used no-parameter constructors…and all the classes match that no-parameter constructor rule – probably ways around it but it will be a bit more coding to deal with that (i.e. it’s not as easy to do as with a normal factory).  And, while this may be a way to dynamically discover classes for your factory, it raises some security concerns as well so code accordingly.  So, use at your own risk basically.

Ok, enough with the legal warnings and notices.  On to the code…

Brief Introduction to Reflection (as it pertains to Dynamic Factories)

So, the first question is how do we find out what classes are within a file?  .Net actually makes this fairly simple…we have to load the assembly (i.e. dll or exe) into memory, then we can get all the types within that file.  Essentially the code to do this is:

Code Snippet
  1. Assembly assembly = Assembly.LoadFrom(filename);
  2. Type[] types = assembly.GetTypes();

Where filename is the full path to an exe or dll that we want to inspect.

Discovering Interested Types

Next, we just iterate over all the types to see if they match what we’re looking for.  We’ve got to be careful here as a type could be an interface, an abstract class, or not even a class that we’re interested in.  For this, I’ve written a routine to verify a type is what I’m interested in.

Code Snippet
  1. protected static bool IsValidAnimal(Type type, ref AbstractAnimalBase animal)
  2. {
  3.     //is it a sub-class
  4.     if (type.BaseType != null)
  5.     {
  6.         //make sure it's not an interface
  7.         if (!type.IsInterface)
  8.         {
  9.             //is it a sub-class of what we're interested in
  10.             if (type.IsSubclassOf((typeof(AbstractAnimalBase))))
  11.             {
  12.                 //make sure the type is a concrete type (i.e. not abstract)
  13.                 if (!type.IsAbstract)
  14.                 {
  15.                     try
  16.                     {
  17.                         animal = (AbstractAnimalBase)type.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { });
  18.                         return true;
  19.                     }
  20.                     catch (Exception ex)
  21.                     {
  22.                         throw new Exception(String.Format("Failed to load {0} as a add on command from {1}", type.Name, type.AssemblyQualifiedName), ex);
  23.                     }
  24.                 }
  25.             }
  26.         }
  27.     }
  28.     return false;
  29. }

So, to put the loading all together into a single class…

AnimalLoader.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4.  
  5. public class AnimalLoader
  6. {
  7.     public static List<AbstractAnimalBase> LoadAnimals(string filename)
  8.     {
  9.         List<AbstractAnimalBase> animals = new List<AbstractAnimalBase>();
  10.         Assembly assembly = Assembly.LoadFrom(filename);
  11.         Type[] types = assembly.GetTypes();
  12.  
  13.         foreach (Type type in types)
  14.         {
  15.             AbstractAnimalBase animal = null;
  16.             if (IsValidAnimal(type,ref animal))
  17.             {
  18.                 animals.Add(animal);
  19.             }
  20.         }
  21.         return animals;
  22.     }
  23.  
  24.     protected static bool IsValidAnimal(Type type, ref AbstractAnimalBase animal)
  25.     {
  26.         //is it a sub-class
  27.         if (type.BaseType != null)
  28.         {
  29.             //make sure it's not an interface
  30.             if (!type.IsInterface)
  31.             {
  32.                 //is it a sub-class of what we're interested in
  33.                 if (type.IsSubclassOf((typeof(AbstractAnimalBase))))
  34.                 {
  35.                     //make sure the type is a concrete type (i.e. not abstract)
  36.                     if (!type.IsAbstract)
  37.                     {
  38.                         try
  39.                         {
  40.                             animal = (AbstractAnimalBase)type.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { });
  41.                             return true;
  42.                         }
  43.                         catch (Exception ex)
  44.                         {
  45.                             throw new Exception(String.Format("Failed to load {0} as a add on command from {1}", type.Name, type.AssemblyQualifiedName), ex);
  46.                         }
  47.                     }
  48.                 }
  49.             }
  50.         }
  51.         return false;
  52.     }
  53. }

Ok, so we can now load the animals that’re in a dll or exe, but how do we load them into our factory?  Need a key for each of the animals and also a way to load them before the factory is first used.

Making the Abstract Class “Keyable”

Well, we actually have a key in the AbstractAnimalBase class but it’s protected – let’s fix that and make it public so that the factory can access the keys (yes, it can be marked as internal instead as long as the factory and animal base class are in the same exe or dll).  So the new AbstractAnimalBase class is changed to:

AbstractAnimalBase.cs
  1. public abstract class AbstractAnimalBase
  2. {
  3.     public string AnimalType { get; private set; }
  4.  
  5.     public AbstractAnimalBase(string type)
  6.     {
  7.         AnimalType = type;
  8.     }
  9.  
  10.     public void IntroduceSelf()
  11.     {
  12.         System.Console.WriteLine(IntroductionLine);
  13.         System.Console.WriteLine(Speak);
  14.         System.Console.WriteLine();
  15.     }
  16.  
  17.     protected virtual string IntroductionLine
  18.     {
  19.         get
  20.         {
  21.             string introLine = "Hello, I am a " + AnimalType;
  22.             return introLine;
  23.         }
  24.     }
  25.  
  26.     protected abstract string Speak
  27.     {
  28.         get;
  29.     }
  30. }

Dynamic Factory Class

Now, to get that factory working.  What would be nice would be for the factory to load the add ins when it’s first used…well, it can – by using a static constructor.

AnimalFactory.cs
  1. public static class AnimalFactory
  2. {
  3.     private static Dictionary<string, AbstractAnimalBase> Animals { get; set; }
  4.  
  5.     static AnimalFactory()
  6.     {
  7.         Animals = new Dictionary<string, AbstractAnimalBase>();
  8.  
  9.         List<AbstractAnimalBase> animals;
  10.         
  11.         string filename="Animals.dll";
  12.         string path=Assembly.GetExecutingAssembly().Location;
  13.         path=System.IO.Path.GetDirectoryName(path);
  14.         string fileToLoad=System.IO.Path.Combine(path,filename);
  15.  
  16.         try
  17.         {
  18.             animals = AnimalLoader.LoadAnimals(fileToLoad);
  19.  
  20.             foreach (AbstractAnimalBase animal in animals)
  21.             {
  22.                 string animalType = animal.AnimalType.ToLower().Trim();
  23.                 if (!Animals.ContainsKey(animalType))
  24.                 {
  25.                     Animals.Add(animalType, animal);
  26.                 }
  27.                 else
  28.                 {
  29.                     throw new Exception(String.Format("Duplicate animal type {0} found", animalType));
  30.                 }
  31.             }
  32.         }
  33.         catch (Exception ex)
  34.         {
  35.             throw new Exception(String.Format("There was a problem loading the assembly {0}", fileToLoad),ex);
  36.         }
  37.     }

For this factory, for demo purposes, I’ve set the filename to be a static dll named Animals.dll, which the static constructor will use to pass to the AnimalLoader – you’ll more than likely want to use something different, but, remember, static constructors cannot accept parameters so you’ll have to find another way or just loop through all dlls.  Also, this uses the current executing path – change as needed for your own purposes.  Really, not a lot here – animals are discovered and loaded by the AnimalLoader method, then the animal types and the animal are added to the static list of animals for the factory.  If you’ve been paying attention, yes, this is a cached factory at this point as reflection is slow.

Now, for getting the animals out of the factory.

AnimalFactory.cs
  1. public static AbstractAnimalBase GetCachedAnimal(string type)
  2. {
  3.     type=type.ToLower().Trim();
  4.     if (Animals.ContainsKey(type))
  5.     {
  6.         return Animals[type];
  7.     }
  8.     else
  9.     {
  10.         throw new Exception(String.Format("Unknown animal type {0}", type));
  11.     }
  12. }
  13.  
  14. public static AbstractAnimalBase GetAnimal(string type)
  15. {
  16.     AbstractAnimalBase cachedAnimal = GetCachedAnimal(type);
  17.     Type animalAssemblyType = cachedAnimal.GetType();
  18.  
  19.     AbstractAnimalBase animal = (AbstractAnimalBase)animalAssemblyType.Assembly.CreateInstance(animalAssemblyType.FullName);
  20.     return animal;
  21. }

Two things to notice here, there’s a method to get a cached animal as well as creating a new one based on the cached version.  I’ve supplied both just to show how to get a new animal from a cached version (this could also work for a normal cached factory as well as one using reflection to dynamically add classes).

Discovering what is available

And, that pretty much wraps up the factories and how to load classes dynamically.  What, you want to know what types are available to show to your UI?  Ok, here’s how you do that (requires “using System.Linq” namespace to be added thanks to the ToList extension method)…

AnimalFactory.cs
  1. public static List<string> GetAnimalTypes()
  2. {
  3.     return Animals.Keys.ToList<string>();
  4. }

Dynamic Cached Factory Code

Now, for all the dynamic cached factory code.

AbstractAnimalBase
  1. using System;
  2.  
  3. public abstract class AbstractAnimalBase
  4. {
  5.     public string AnimalType { get; private set; }
  6.  
  7.     public AbstractAnimalBase(string type)
  8.     {
  9.         AnimalType = type;
  10.     }
  11.  
  12.     public void IntroduceSelf()
  13.     {
  14.         System.Console.WriteLine(IntroductionLine);
  15.         System.Console.WriteLine(Speak);
  16.         System.Console.WriteLine();
  17.     }
  18.  
  19.     protected virtual string IntroductionLine
  20.     {
  21.         get
  22.         {
  23.             string introLine = "Hello, I am a " + AnimalType;
  24.             return introLine;
  25.         }
  26.     }
  27.  
  28.     protected abstract string Speak
  29.     {
  30.         get;
  31.     }
  32. }

 

Dog.cs
  1. using System;
  2.  
  3. public class Dog : AbstractAnimalBase
  4. {
  5.     public Dog()
  6.         : base("Dog")
  7.     {
  8.     }
  9.  
  10.     protected override string Speak
  11.     {
  12.         get { return "Woof"; }
  13.     }
  14. }

 

Cat.cs
  1. using System;
  2.  
  3. public class Cat : AbstractAnimalBase
  4. {
  5.     public Cat()
  6.         : base("Cat")
  7.     {
  8.     }
  9.  
  10.     protected override string Speak
  11.     {
  12.         get { return "Meow"; }
  13.     }
  14. }

 

Pig.cs
  1. using System;
  2.  
  3. public class Pig : AbstractAnimalBase
  4. {
  5.     public Pig()
  6.         : base("Pig")
  7.     {
  8.     }
  9.  
  10.     protected override string Speak
  11.     {
  12.         get { return "Oink"; }
  13.     }
  14. }

 

AnimalLoader.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4.  
  5. public class AnimalLoader
  6. {
  7.     public static List<AbstractAnimalBase> LoadAnimals(string filename)
  8.     {
  9.         List<AbstractAnimalBase> animals = new List<AbstractAnimalBase>();
  10.         Assembly assembly = Assembly.LoadFrom(filename);
  11.         Type[] types = assembly.GetTypes();
  12.  
  13.         foreach (Type type in types)
  14.         {
  15.             AbstractAnimalBase animal = null;
  16.             if (IsValidAnimal(type, ref animal))
  17.             {
  18.                 animals.Add(animal);
  19.             }
  20.         }
  21.         return animals;
  22.     }
  23.  
  24.     protected static bool IsValidAnimal(Type type, ref AbstractAnimalBase animal)
  25.     {
  26.         //is it a sub-class
  27.         if (type.BaseType != null)
  28.         {
  29.             //make sure it's not an interface
  30.             if (!type.IsInterface)
  31.             {
  32.                 //is it a sub-class of what we're interested in
  33.                 if (type.IsSubclassOf((typeof(AbstractAnimalBase))))
  34.                 {
  35.                     //make sure the type is a concrete type (i.e. not abstract)
  36.                     if (!type.IsAbstract)
  37.                     {
  38.                         try
  39.                         {
  40.                             animal = (AbstractAnimalBase)type.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { });
  41.                             return true;
  42.                         }
  43.                         catch (Exception ex)
  44.                         {
  45.                             throw new Exception(String.Format("Failed to load {0} as a add on command from {1}", type.Name, type.AssemblyQualifiedName), ex);
  46.                         }
  47.                     }
  48.                 }
  49.             }
  50.         }
  51.         return false;
  52.     }
  53. }

 

AnimalFactory.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Linq;
  5.  
  6. public static class AnimalFactory
  7. {
  8.     private static Dictionary<string, AbstractAnimalBase> Animals { get; set; }
  9.  
  10.     static AnimalFactory()
  11.     {
  12.         Animals = new Dictionary<string, AbstractAnimalBase>();
  13.  
  14.         List<AbstractAnimalBase> animals;
  15.  
  16.         string filename = "Animals.dll";
  17.         string path = Assembly.GetExecutingAssembly().Location;
  18.         path = System.IO.Path.GetDirectoryName(path);
  19.         string fileToLoad = System.IO.Path.Combine(path, filename);
  20.  
  21.         try
  22.         {
  23.             animals = AnimalLoader.LoadAnimals(fileToLoad);
  24.  
  25.             foreach (AbstractAnimalBase animal in animals)
  26.             {
  27.                 string animalType = animal.AnimalType.ToLower().Trim();
  28.                 if (!Animals.ContainsKey(animalType))
  29.                 {
  30.                     Animals.Add(animalType, animal);
  31.                 }
  32.                 else
  33.                 {
  34.                     throw new Exception(String.Format("Duplicate animal type {0} found", animalType));
  35.                 }
  36.             }
  37.         }
  38.         catch (Exception ex)
  39.         {
  40.             throw new Exception(String.Format("There was a problem loading the assembly {0}", fileToLoad), ex);
  41.         }
  42.     }
  43.  
  44.     public static AbstractAnimalBase GetCachedAnimal(string type)
  45.     {
  46.         type = type.ToLower().Trim();
  47.         if (Animals.ContainsKey(type))
  48.         {
  49.             return Animals[type];
  50.         }
  51.         else
  52.         {
  53.             throw new Exception(String.Format("Unknown animal type {0}", type));
  54.         }
  55.     }
  56.  
  57.     public static AbstractAnimalBase GetAnimal(string type)
  58.     {
  59.         AbstractAnimalBase cachedAnimal = GetCachedAnimal(type);
  60.         Type animalAssemblyType = cachedAnimal.GetType();
  61.  
  62.         AbstractAnimalBase animal = (AbstractAnimalBase)animalAssemblyType.Assembly.CreateInstance(animalAssemblyType.FullName);
  63.         return animal;
  64.     }
  65.  
  66.     public static List<string> GetAnimalTypes()
  67.     {
  68.         return Animals.Keys.ToList<string>();
  69.     }
  70. }