I know the answer (it's 42)

A blog on coding, .NET, .NET Compact Framework and life in general....

November, 2005

Posts
  • I know the answer (it's 42)

    C# 2.0: Using different versions of the same dll in one application

    • 31 Comments

    Lot of things have become really easy to do in C#2.0. I needed to load 2 versions of the same class library dll in my application. The format of output file had changed between versions. So I need to deserialize an xml using the older version and then convert it to the newer version and then serialize it out.  So at the same time I needed to load both the old and new dlls. Lets assume that you have the following implementation of the class libraries

    Older version

    using System;

    namespace MyLibrary

    {

    public class MyClass

    {

    public static string method()

    {

    return "From old version ClassLibrary2";

    }

    }

    }

    Newer version

    using System;

    namespace MyLibrary

    {

    public class MyClass

    {

    public static string method()

    {

    return "From new version ClassLibrary2";

    }

    }

    }

    The structure of both libraries are exactly the same and they have the same namespace and classes and only differ in implementation. If I add reference to both the class library dlls and try to access the methods in the client using the following code

    using System;

    using System.Text;

    namespace ClientApp

    {

    class Program

    {

    static void Main(string[] args)

    {

    Console.WriteLine(MyLibrary.MyClass.method());

    }

    }

    }

    Compilation will fail with the error "The type 'MyLibrary.MyClass' exists in both 'Somepath\ClassLibrary.dll' and 'AnotherPath\ClassLibrary.dll'". The reason being that the access becomes ambiguous. 

    This is where the new namespace alias qualifier and the extern alias comes into the picture. First we write the client application (program.cs) as

    extern alias oldVer;

    extern alias newVer;

    using System;

    using System.Text;

    namespace ClientApp

    {

    class Program

    {

    static void Main(string[] args)

    {

    Console.WriteLine(oldVer::MyLibrary.MyClass.method());

    Console.WriteLine(newVer::MyLibrary.MyClass.method());

    }

    }

    }

    In the code-snippet above all the important bits are marked in bold. The extern alias declaration creates a namespace parallel to the global namespace. Pre C#2.0 all namespaces were rooted at the global namespace, which is no more the case. We are telling the compiler that two other namespace oldVer and newVer exists which are externally defined. We now use the :: operator to access inside the namespace alias. We could have used the regular . qualifier but the :: qualifier ensures that the identifier on the left-hand of the :: qualifier is an extern or using alias.

    The next step is to define the external alias. We can do it using the command line as follows

    csc /r:oldVer=Somepath\ClassLibrary.dll /r:newVer=AnotherPath\ClassLibrary.dll program.cs

    So the contents of the older version is loaded under the oldVer alias and the new version under newVer. So all access ambiguity is removed.

    The same thing can also be acheived using the VS IDE. Add the reference to both the dlls in your client application solution. Then in the Solution Explorer under the reference node select the first (old version) class library. In the property window change Aliases field from global to oldVer. Make similar change after selecting the newer class library as well. You are then good to go....

  • I know the answer (it's 42)

    C# 2.0: no more lexer blues with nested templates

    • 0 Comments
    When generics got announced and I laid my hands on the C#2.0 compiler the first thing I tried is nested template usage. This C++ compiler (spec actually) gave me enough pain with this. Consider the following C++ code which uses the STL.

    #include "vector"

    using namespace std;

    int main()

    {

    vector<int> vectorI;

    vectorI.push_back(5);

    vector<vector<int>> vectorV;

    vectorV.push_back(vectorI);

    return 0;

    }

    First glance indicates that the line in bold is trying to create a vector of vectors. This is where the infamous C++ lexer blue starts. The lexer thinks that the >> is actually the right-shift operator and spits out an error. On some compiler the error is very cryptic and is something like "undefined symbol vectorV" on some its clearer and is "space required between adjacent ">" delimiters of nested template argument lists". The solution in C++ is to use a space between the two > and write it as

    vector<vector<int> > vectorV;

    Since I always forgot the space in my first attempt, I landed up swearing when I got this error. However many C++ compiler choose to deviate from the C++ spec and actually act intelligently and treat the consecutive >> as nested template delimiters based on context. I tried the above sample on Microsoft C++ compiler 14.00.50727.18 and it worked. So either MS compiler deviates from the C++ spec or maybe C++ spec has changed (I am not following the C++ world for a long time now....)

    The fact that this was a major pain in C++ helped in the design of C#. With C# 2.0 the >> and >>= tokens got removed from the lexical grammer (See the §20.10 in the 2.0 spec) and replaced with new assignment productions. So there is no requirement for the extra space in between >> in C#. So a similar code in C# is like

    List<int> listI = new List<int>();

    listI.Add(5);

    List<List<int>> listL = new List<List<int>>(); // no space reqd

    listL.Add(listI);

  • I know the answer (it's 42)

    C#: PG required, obscene case fall through code and Duff device

    • 6 Comments

    I had said before that I miss case fall through in C# and I promised that I'd write about some weird uses of this feature in C++. 

    I think the weirdest use of case statement was made by Tom Duff. He needed to write some code in C that copied an array of shorts into a pre-programmed IO data register. The code looked like

    void loopSend(register short* to, register short* from, register int count)

    {

    do

    *to = *from++;

    while(--count > 0);

    }

    The compiler emitted instructions to compare the count with zero after each copying each short. This had a considerable perf hit and so he decided to apply common loop unrolling technique. This is where things became extremely weird. He used a little-known C feature in which switch-case statements can be inter-leaved with other statements. The optimized code looked like

    void send(register short *to, register short *from, register int count)

    {

    register int n=(count+7)/8;

    switch(count%8){

    case 0: do{ *to = *from++;

    case 7: *to = *from++;

    case 6: *to = *from++;

    case 5: *to = *from++;

    case 4: *to = *from++;

    case 3: *to = *from++;

    case 2: *to = *from++;

    case 1: *to = *from++;

    }while(--n>0);

    }

    }

    If you are wondering if its legal C, then think again, as this is not only legal C, it's legal C++ as well. If you change all *to to *to++ this becomes a memcpy code which is more relevant to most programmers. When I first saw this is college, I had to actually step through the code to figure out how it worked and then kept wondering why there was no obscene code warning before the code and so I made it a point to add it in the blog title :)

    Some people took this to the extreme and created a stack based co-routine. People who take yield return for granted should try understanding the following

    #define crBegin static int state=0; switch(state) { case 0:

    #define yieldReturn(i,x) do { state=i; return x; case i:; } while (0)

    #define crFinish }

    int function(void) {

    static int i;

    crBegin;

    for (i = 0; i < 10; i++)

    yieldReturn(1, i);

    crFinish;

    }

     

  • I know the answer (it's 42)

    C# : I hate commented out code

    • 11 Comments

    Even though retaining commented lines of code in your source-base is not a good thing, it's a fact that they do exist. Whenever I see a chunk of code commented out I first make a yucky face and then the next thing that comes to my mind is why did someone do this (was he unsure??) and in case it was required, how they hell do I find out all such commented blocks of code and clean up the files.

    How you comment out code in a large project heavy impacts whether all such code will be found easily and cleaned (or in some cases un-commented). There are multiple styles people use and some of them are bad practices. The so called *advanced* editor features in the IDE aggravates this to a great deal. Some of the common styles I have encountered are listed below

    Multi-line comment

    This was the most common way of commenting out code in the C++ era, however this is less used in C#

    /*foreach (IMotionDetector detector in list)

    {

    Console.WriteLine("{0} ({1})", detector.Name, detector.Description);

    }*/

    If you have a coding standard in place which does not allow multi-line comments anywhere else in your code then you might live with this. However, if you have a thousand place in the source base that uses this (as in copy-right notice on top of each file and block comments on top of all public methods)  then you'll be in deep trouble to find this piece out. The only advantage of this method is that its really simple to uncomment the code using any editor.

    The single line comment

    This irritates me the most

    //foreach (IMotionDetector detector in list)

    //{

    // Console.WriteLine("{0} ({1})", detector.Name, detector.Description);

    //}

    Any source base will have thousands of // scattered every-where, so how the hell am I supposed to find code commented out in this fashion?

    This is worsened by the fact that the VS IDE has the cool (???) Edit->Advanced->Comment Selection feature which actually uses this format to comment out a block of selected code. If you are using the same editor or some other editor which has the corresponding uncomment feature then you are fine. If you are unfortunate enough to like some other editor like notepad (or is being forced to use another editor due to some constrains) then happy hunting. Go to the beginning of each line and hit del twice :(

    #if <token> ... #endif

    #if comment

    foreach (IMotionDetector detector in list)

    {

    Console.WriteLine("{0} ({1})", detector.Name, detector.Description);

    }

    #endif

    I think this is the only style that renders commented code easy to find. You can just do a search for #if comment or some other token and get to each of these. The developers using the VS IDE will be happy because VS is intelligent enough to gray out the code enclosed in #if token when token is not defined. The only issue is that if someone goes and #defines comment. So the really safe thing to do is use #if false

    #if false

    foreach (IMotionDetector detector in list)

    {

    Console.WriteLine("{0} ({1})", detector.Name, detector.Description);

    }

    #endif

    Do you really need the commented piece of code

    Before keeping commented-out code you really need to think twice (maybe thrice). Almost all projects use source-control so you can always get back to the code once it gets deleted. If you decide on leaving the code, add a comment on top indicating why you commented it out and why you think you'll need it back in the future.

  • I know the answer (it's 42)

    TeamBuild: Scheduled build using Team System

    • 10 Comments

    Sorry to all the folks who read my blog for C#. This ones about Team System and specifically about the Team Build module :)

    Team Build does not have any in-built scheduler and so it does not provide scheduled builds out of the box. However, it does have a command line tool to start team-builds. Any scheduler like the Windows Task Scheduler can be easily setup to use this command line Team Build utility to start builds at predetermined time. The Task Scheduler can be setup using a simple batch file or manually using the Add Scheduled task wizard that comes with Windows.

    Where do I setup the scheduler?
    Since the scheduler will use the command line TfsBuild.exe utility, you'll need to start the scheduler on either any one of the TFS clients or on a Build Machine.

    Doing it through the Scheduled Task Wizard
    To open Scheduled Tasks on Windows XP or Windows 2003, click Start, click All Programs, point to Accessories, point to System Tools, click Scheduled Tasks and then Add Scheduled Task. Then choose the TfsBuild.exe (ProgramFiles\Microsoft Visual Studio 8\Common7\IDE\TfsBuild.exe) as the executable and set the schedule and the account information under which you want to run the TfsBuild. At the last page ensure that the "Open advanced properties..." is checked before you hit finish...

    In the dialog that opens enter the arguments in the Run text box so that its like...

    "d:\Program Files\Microsoft Visual Studio 8\Common7\IDE\TfsBuild.exe" start <TfsServer> <Team Project> <Build Type name>

    Doing it through a batch file
    I wrote a simple batch file that makes this even easier. Copy/paste the following into a file named schbuild.bat and place it in %ProgramFiles%\Microsoft Visual Studio 8\Common7\IDE and run schbuild.bat to see usage.

    @echo off
    
    if "%1" == "" goto Help
    if /i "%1" == "-h" goto Help
    
    set server=%1
    set project=%2
    set buildType=%3
    
    set schedule=%4
    set startTime=%5
    set startDate=%6
    
    set schName=%2_%3
    
    set tfsCommand="D:\PROGRA~1\MID05A~1\Common7\IDE\TfsBuild.exe start %server% %project% %buildType%"
    
    set user=%userdomain%\%username%
    echo %tfsCommand%
    
    schtasks /create /sc %schedule% /tn %schName% /tr %tfsCommand% /st %startTime% /sd %startDate% /ru %user% /rp *
    Goto Done
    
    :Help
    @echo Usage: schbuild TeamfoundationServer TeamProject BuildType Schedule StartTime StartDate
    @echo.
    @echo     TeamfoundationServer   The Team Foundation server.
    @echo.
    @echo     TeamProject            Team project name.
    @echo.
    @echo     BuildType              Build Type name.
    @echo.
    @echo     Schedule               Specifies the schedule frequency. 
    @echo                            Valid schedule types: MINUTE, HOURLY,
    @echo                            DAILY, WEEKLY, MONTHLY, ONCE.
    @echo.
    @echo     StartTime              Time to start the build in HH:MM:SS 
    @echo                            (24 hour format)
    @echo.
    @echo     StartDate              Specifies the first date on which the
    @echo                            task runs. The format is mm/dd/yyyy.
    
    :Done

    Sample batch file run
    To start a nightly build that happens every night at 9:00p.m. use something like

    SchBuild.bat MyTfsServer MyTeamProject  NightlyBuildType DAILY 21:00:00 11/21/2205

    Customizing the Schedule
    Once the Team Build has been scheduled through the batch file it can be easily modified using the scheduled tasks user interface. To open Scheduled Tasks use the same steps as mentioned above and then double click on the task named <Team project>_<BuildType> to open it and modify as required.

  • I know the answer (it's 42)

    C#: I miss case fall through

    • 31 Comments

    We all have heard time and again that the default case fall through is not good (as in C/C++) and C# does not allow it. There has been enough debate on this but I still differ on this. I used to like it a lot and somehow when I do need to use it the following puts me off big time!!!

    switch(value)

    {

    case 0:

    Console.WriteLine("In case 0\n");

    goto case 1;

    case 1:

    Console.WriteLine("In case 1\n");

    goto case 2;

    case 2:

    Console.WriteLine("In case 2\n");

    break;

    }

    I kind of do not buy the statement that case-statement fall through results in issues in the maintainence phase. Its pointed out that fall-through can lead to the following

    1. Developer forgets to add the break at the end and un-intentional fall-through may happen
    2. Case statements cannot be easily reordered as the fall-through execution may vary...

    With C lying around for 30 years and C++ over 20 years most developers have got used to adding break at the end of case. In case C# wanted to do something for new developers or for developers moving in from languages like VB, a warning could have been added in case break is missing, asking the developer if fall-through is the intent. This is very similiar to the warning given for the following code

    bool hello;

    // lots of code....

    if (hello = true) // this is why some people use true == hello

       Console.WriteLine(arg);

    Warning 1 Assignment in conditional expression is always constant; did you mean to use == instead of = ?

    What I also do not understand is the requirement for the break statement at the end of each case in C# even though it does not support fall-through.

    switch (arg)

    {

    case "0":

    Console.WriteLine(0);

    //break;

    case "1":

    Console.WriteLine(1);

    break;

    }

    The above code fails to compile and you need to uncomment the //break to get it to compile. The error is "Control cannot fall through from one case label ('case "0":') to another" Since the language clearly states that fall-through do not happen then why do I need to add the extra break, it has no purpose and I should not be required to add it. This looks like to have been added to aid C/C++ developers to understand that fall through does not happen. I feel that this error should have been the warning I had mentioned above....

    There are a lot of interesting or weird uses of fall-through and the fact that switch can be interlaced with statement blocks (thats in the next post...).

  • I know the answer (it's 42)

    C# 2.0: Loading plugins at run-time using late binding

    • 29 Comments

    I was working on a home project for creating a motion-detector that works using a webcam. Instead of using a baby-monitor I am planning to run this on an old computer. I'll point the web-cam to my daugthers' crib and the program would monitor both sound and her motions and ring an alarm in case she moves or makes any noise.

    While working on this I wrote some code to support plugins to the application so that I can choose and use any motion-detection algorithm that I want. Some time back there was some questions on our internal DL about using late-binding to load and execute code. So I thought I'd blog about the code I used for the plugin loading and executing.

    I used the following steps for this

    • List all dlls is a directory (plugins directory)
    • Load all assemblies from this dir
    • Iterate through all the types in the assembly and look if the type implements the plugin interface
    • Create an instance of the type that implement the interface and store it in a List

    To do all of the above I wrote the following generic method that given any interface and a folder name can create a List of instances of all types that implement the plugin interface.

    using System.Reflection;

    using System.Collections.Generic;

    public List<T> GetPlugins<T>(string folder)

    {

    string[] files = Directory.GetFiles(folder, "*.dll");

    List<T> tList = new List<T>();

    Debug.Assert(typeof(T).IsInterface);

     

    foreach (string file in files)

    {

    try

    {

    Assembly assembly = Assembly.LoadFile(file);

    foreach (Type type in assembly.GetTypes())

    {

    if (!type.IsClass || type.IsNotPublic) continue;

    Type[] interfaces = type.GetInterfaces();

    if (((IList)interfaces).Contains(typeof(T)))

    {

    object obj = Activator.CreateInstance(type);

    T t = (T)obj;

    tList.Add(t);

    }

    }

    }

    catch (Exception ex)

    {

    LogError(ex);

    }

    }

    return tList;

    }

    With this method I can write code to show the list of plugins with their description in a menu or list control as follows

    string exeName = Application.ExecutablePath;

    string folder = Path.Combine(Path.GetDirectoryName(exeName), "Plugins");

    List<IMotionDetector> list = GetPlugins<IMotionDetector>(folder);

     

    m_listPlugin.Items.Clear(); // list box

    foreach (IMotionDetector detector in list)

    {

    string name = detector.GetPluginName();

    string desc = detector.GetPluginDescription();

    string str = string.Format("{0}, {1}, {2}",

    detector.GetType().FullName, name, desc);

    m_listPlugin.Items.Add(str);

    }

    The interface I used is defined as

    using System;

    using System.Drawing;

    namespace MotionDetector

    {

    // Event fired by the plugin on detecting motion

    public delegate void MotionEvent(object sender, EventArgs args);

    public interface IMotionDetector

    {

    // Plugin information - Since plugin det

    string GetPluginName();

    string GetPluginDescription();

     

    void SetImage(Bitmap bitmap);

    void Reset();

    event MotionEvent Motion;

    }

    }

    Since I used generics I marked the blog title with C#2.0.

  • I know the answer (it's 42)

    C# 2.0: get and set accessor can have different accessibility

    • 9 Comments

    One of the issues with properties in C#1.x is that the get and the set accessors get the same accessibility. In some situations you'd want to impose more usage restriction on the set accessor then on get . In the following sample both the get and set are public.

    class Employee

    {

    private string m_name;

    public string Name {

    get { return m_name; }

    set { m_name = value; }

    }

    }

    class Program

    {

    static void Main(string[] args) {

    Employee emp = new Employee();

    emp.Name = "Abhinaba Basu";

    }

    }

    In case you want set to be more restricted than get you have no direct way of getting it done in C#1.x (other than splitting them into different properties). In C# 2.0 its possible to have different accessibility on get and set accessors using accessor-modifier. The following code gives protected access to set and public to get

    class Employee

    {

    private string m_name;

    public string Name

    {

    get { return m_name; }

    protected set { m_name = value; }

    }

    }

    class Program

    {

    static void Main(string[] args) {

    Employee emp = new Employee();

    emp.Name = "Abhinaba Basu"; // Will fail to compile

    }

    }

    This is really cool because in many designs I have felt the need to make set accessor protected and allow get to be internal or public. With this addition to C# this becomes easy to do.

    There are however lot of gotchas and cases to consider before going ahead and blindly using this. I have listed some which I found need to be considered....

    • Accessor-modifiers cannot be used in an interfaces or explicit interface implementation
    • The modifier must be more restrictive than the accessibility of the property. So if the property is declared as protected then the modifier can only be private
    • Accessor-modifier does not effect member lookup.

    Be sure to check the C# spec before using this feature as there are some subtleties specially in terms of member lookup....

  • I know the answer (it's 42)

    C#: Why I cannot call protected method from derived class

    • 4 Comments

    Someone posted a comment in the internal alias on protected member access. The question is that the following code does not compile with the error "cannot access protected member Class1.Foo()"

    public class Class1

    {

    protected void Foo()

    {

    }

    }

    public class Class2 : Class1

    {

    private void Test()

    {

    Class2 a = new Class2();

    Class1 b = new Class2();

    a.Foo();

    b.Foo(); // Fails to compile

    }

    }

    The argument that this code should work is that since Class1 is the base class of Class2 the access should be allowed. Long back (in another life) I had seen the same issue in C++. This is what I replied to the question....

    The same issue exists in C++ as well, I think similar rationale will exist for C#. The following C++ code won’t compile as well

    class Class1

    {

    protected:

    void Foo ()

    {

    }

    };

    class Class2 : public Class1

    {

    public:

    void Test ()

    {

    Class2* a = new Class2 ();

    Class1* b = new Class2 ();

    a->Foo();

    b->Foo();

    }

    };

    This is because b is pointer (or reference) to a base class. For all we know b could point to an object of any class derived from Class1. If this call was allowed then it would break encapsulation as you would get access to a method inside the derived class

  • I know the answer (it's 42)

    C#: Uninitialized instance variables

    • 7 Comments

    int i;

    Console.WriteLine(i);

    The above code will fail to compile. This is because the C# compiler requires a variable to be definitely assigned at the location where it is used. It figures this out using static flow analysis and the above case is the easiest catch for it.

    However, there is a small trivia regarding this. Lets consider the following code

    class MyClass

    {

    public int i;

    public MyClass()

    {

    }

    }

    class Program

    {

    static void Main(string[] args)

    {

    MyClass myclass = new MyClass();

    Console.WriteLine(myclass.i);

    }

    }

    This piece of code will compile and run and the output will be 0. A first look reveals that i has not been initialized as i is not static and we have not initialized it in the constructor of MyClass, but still it is initialized to 0. The reason can be found in the Section 5.3.1 of C# spec. It lists the types of variables that are intially assigned. The list goes as
    • Static variables.
    Instance variables of class instances.
    • Instance variables of initially assigned struct variables.
    • Array elements.
    • Value parameters.
    • Reference parameters.
    • Variables declared in a catch clause or a foreach statement.
    Since instance variables of class instances are initialized the code builds and runs. This can lead to bugs in code as the compiler does not warn on un-initialized instance variables....
  • I know the answer (it's 42)

    C#: Linked by the great Raymond Chen

    • 3 Comments

    So I won an Oscar too :) and was honored with a link from Raymond Chen. Sometime back I posted on including try/catch/retry block in C# and he is recommending not using such automatic retrying. However, I do not agree with the flat recommendation and I think this varies based on the scenario.

    This is what I replied to his post....

    I agree that just retrying does not work in all situation. In  http://blogs.msdn.com/abhinaba/archive/2005/10/01/476026.aspx
    the example I used does not arbitrarily  retry the operation 3 times. It uses an Exception class which explicitly uses a public member to signal whether the operation is retryable.

    In all situations asking the user for retrying does not work. Lets take the example of one of the source code repository converters we are working on. This takes a VSS repository and migrates all data in it to Team Foundation Server repository. This includes thousands of files and hundreds of versions of each of them amounting to 10s of GB of data and takes a day to migrate. In this super-high stress situation VSS server sometimes acts-up and either times-out or throws an error. So what do we do, expect the user to sit around for the whole day and see each failure and prompt him Retry (Y/N)? or fail the migration that was going on for the last 8 hours?

    My point is in some situations like an interactive program (UI client) prompting the user for retry is the correct thing to do. In long running un-attended batch conversion job where we know for sure that transient failures occur and get resolved on retrying, using retry is the right approach.

  • I know the answer (it's 42)

    We're on Channel 9

    • 0 Comments

    Kaushal from Microsoft Bangalore was here in Hyderabad some time back. He shot some video of the folks here, including some from VSTS-Team Build. The video is on http://channel9.msdn.com/Showpost.aspx?postid=143589. See me and Anu giving a demo of Team Build and taking him around to meets folks out here.

     

  • I know the answer (it's 42)

    C# 2.0: The all new ?? operator

    • 7 Comments

    Thanks to James Manning's blog I remembered the new ?? operator introduced in C#2.0 and that very few people seem to use it.

    This new ?? operator is mainly used for nullable types but can also be used with any reference type.

    Use with nullable type

    In case you are converting a nullable type into a non-nullable type using code as follows

    int? a = null;

    // ...

    int e = (int)a;

    You will land into trouble since a is null and an System.InvalidOperationException will be thrown. To do this correctly you first need to define what is the value of int which you'll consider as invalid (I choose -1) and then use any of the following expressions.

    int? a = null;

    // ...

    int e = (a != null) ? (int)a : -1;

    int f = a.HasValue ? a.Value : -1;

    int g = a.GetValueOrDefault(-1);

    This is where the ?? operator comes into play. Its a short hand notation of doing exactly this and you can just use

    int? a = null;

    // ...

    int c = a ?? -1;

    Use with any reference type

    In code many times we compare reference to null and assign values based on it. I made a quick search on some code and found the following code used to write function arguments to a log file

    string localPath = (LocalPath == null ? "<null>" : LocalPath);

    This can be coded easily using

    string localPath = LocalPath ?? "<null>";

     

  • I know the answer (it's 42)

    C# 2.0: Fast string comparison with string-interning

    • 9 Comments

    <Also read the later posting on the same topic>

    Frequently in code we do string comparisons which is culture-agnostic. While we should follow the string comparison guidelines, there is a much faster way of getting it done using string interning.

    As a sample lets take method that accepts a string and does some action based on the string.

    static void ExecuteCommand(string command)

    {

    if (command == "START")

    Console.WriteLine("Starting Build...");

    else if (command == "STOP")

    Console.WriteLine("Stopping Build...");

    else if (command == "DELETE")

    Console.WriteLine("Deleting Build...");

    else

    Console.WriteLine("Invalid command...");

    }

    The problem with this code is that this actually does a full string comparison using string.Equals(command, "START", StringComparison.Ordinal); which results in iterating through each of the bytes of the two strings and comparing them. In case the strings are long and there are a lot of strings to compare, this becomes a slow process. However if we are sure that the string command is an interned string we can make this much faster. Using the following code

    static void ExecuteCommand(string command)

    {

    if (Object.ReferenceEquals(command,"START"))

    Console.WriteLine("Starting Build...");

    else if (Object.ReferenceEquals(command, "STOP"))

    Console.WriteLine("Stopping Build...");

    else if (Object.ReferenceEquals(command, "DELETE"))

    Console.WriteLine("Deleting Build...");

    else

    Console.WriteLine("Invalid command...");

    }

    This uses just the reference comparison (memory address comparison) and is much faster. However, the catch is that the command has to be an interned string. In case the command is not a literal string and is either generated or accepted from the user as a command line argument then this will not be an interned string and the comparisons will always fail. However we can intern it using the following

    string command = string.Intern(args[0].ToUpperInvariant());

    ExecuteCommand(command);

    Here we have taken care of both the case handling as well as ensured that the command is interned. Another generic way of doing this could be

    string internedCmd = string.IsInterned(command) ?? string.Intern(command);

    Here IsInterned returns the interned string if the string is interned of else null. Intern interns the string and returns a reference to it. Interestingly this expression also uses the new ?? C# 2.0 operator.

Page 1 of 1 (14 items)