Search

Month List

Calendar

<<  September 2010  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar

Tag cloud

    Creating a generics based scope class - Part 1

    by Brent VanderMeide 20. June 2008 07:00

    In a series of 3 parts I will walk you through how to create the basic scope class, a nestable scope class, and finally the generics based nestable scope class.

    What is a Scope class? Glossary

    So before we get started, here's some term definitions that will dramatically help clarify the purpose of a scope and how it behaves.

    • Thread Context Storage : A property bag that is associated with the current thread context.  Think of it as having a backpack on the thread in which you can put or get objects in & out of at any time without having to pass them as parameters through method calls

    • On the Thread Context : The process of putting data in the current Thread Context Storage using some key and value

    • Scope class : A design pattern in which while the object is alive stores itself on the thread context until the class is disposed of (via IDisposable.Dispose(), not to be confused with a deconstructor).

    • Nestable Scope class : Same as a Scope class however behaves differently depending upon whether or not a scope of the same type is already existent on the thread context.

    The Basic Scope Class

    I'm hoping that you actually read those above, and not just glanced over them.  It is crucial that you understand all of the terms above.  Now, did you actually read it this time?

    In this basic scope class, let's set out an example to code against.  Let's say we want to identify the total amount of times a particular method (Doodle) is called within an function (Foo).  Here's the example code using a DoodleCounterScope class.

       1:  public void Foo()
    
       2:  {
    
       3:      using(DoodleCounterScope scope = new DoodleCounterScope())
    
       4:      {
    
       5:          Brainstorm(5);
    
       6:          Brainstorm(10);
    
       7:          Console.WriteLine(scope.Count); // Output: 15
    
       8:      }
    
       9:  }
    
      10:  private void Brainstorm(int doodleCount)
    
      11:  {
    
      12:      for (int i = 0; i < doodleCount; i++)
    
      13:          Doodle();
    
      14:  }
    
      15:  private void Doodle()
    
      16:  {
    
      17:      // Increment method counter
    
      18:      DoodleCounterScope.Current.Count += 1;
    
      19:  } 
    

    Ok, now we're going to jump into creating a scope class.  Notice that a scope class works by putting data on the thread context as soon as it becomes alive and only removes once it disposes.  So if we were to look at that, we can extrapolate the following code to start with.

       1:  public class Scope : IDisposable
    
       2:  {
    
       3:      public Scope(){  /* Put [this] on the thread context */  }
    
       4:      public void Dispose(){  /* Remove [this] from the thread context */  }
    
       5:  } 
    

    The example above begins tracking at line 3 and finishes at line 8. So in line 3 we put data on the thread context and line 8 we remove data off the thread context. ( an end of a using block executes IDisposable.Dispose() on the object referenced in the using statement. We use a 'using' block to ensure that regardless of an exception once the thread leaves the scope of the 'using' block, the dispose method is called (hence scope)  ) 

    Using the CallContext class in the System.Runtime.Remoting.Messaging namespace we can put and remove data on and off the thread.  There are two sets of static functions seperating the behavior of the storage.  The plain SetData and GetData works with an object on the current thread only.  The more sophisticated LogicalSetData and LogicalGetData works with data on the current thread, carries over to any spawned threads, and through remoting channels.  To be able to use the logical call methods, LogicalSetData and LogicalGetData, the object must be serializable and implement the marker interface ILogicalThreadAffinative in the System.Runtime.Remoting.Messaging namespace.

    The CallContext stores and retrieves objects by a string name identifier.  To remove data off of the thread you must call CallContext.FreeNamedDataSlot.  The GetData & LogicalGetData methods only retrieve a reference to the object on the thread with the specified name (not clearing the name).  If you do not free the named data slot on the thread your object will not dispose until the thread is abandoned and disposed of.

    Knowing all of that, let's move forward.  Let's rename the Scope class to match our example DoodleCounterScope

       1:  public class DoodleCounterScope : IDisposable
    
       2:  {
    
       3:      public DoodleCounterScope(){  /* Put [this] on the thread context */  }
    
       4:      public void Dispose(){  /* Remove [this] from the thread context */  }
    
       5:  }
    

    Now let's mark the class as serializable and implement the marker interface ILogicalThreadAffinative

       1:  [Serializable]
    
       2:  public class DoodleCounterScope : IDisposable, ILogicalThreadAffinative
    
       3:  {
    
       4:      public DoodleCounterScope(){  /* Put [this] on the thread context */  }   
    
       5:      public void Dispose(){  /* Remove [this] from the thread context */  }
    
       6:  } 
    

    Next let's put the constructor and disposing logic in place for lines 4 and 5

       1:  [Serializable]
    
       2:  public class DoodleCounterScope : IDisposable, ILogicalThreadAffinative
    
       3:  {
    
       4:      public DoodleCounterScope()
    
       5:      {
    
       6:          // Put [this] on the thread context
    
       7:          CallContext.LogicalSetData("DoodleCounterScope", this);
    
       8:      }
    
       9:   
    
      10:      public void Dispose()
    
      11:      {
    
      12:          // Remove [this] from the thread context
    
      13:          CallContext.FreeNamedDataSlot("DoodleCounterScope");
    
      14:      }
    
      15:  }
    

    Look back at our example use of this DoodleCounterScope at line 18.  The Doodle method gets a reference to our scope object through a DoodleCounterScope.Current static property and then increments a Count property.  Now it's important to note that the Current property is static.  The key differrence of using a scope class is that the static property will be returning a thread specific variable not a shared static variable.  Let's add that Current property.

       1:  [Serializable]
    
       2:  public class DoodleCounterScope : IDisposable, ILogicalThreadAffinative
    
       3:  {
    
       4:      public static DoodleCounterScope Current
    
       5:      {
    
       6:          get
    
       7:          {
    
       8:              return CallContext.LogicalGetData("DoodleCounterScope") as DoodleCounterScope;
    
       9:          }
    
      10:      }
    
      11:   
    
      12:      public DoodleCounterScope()
    
      13:      {
    
      14:          // Put [this] on the thread context
    
      15:          CallContext.LogicalSetData("DoodleCounterScope", this);
    
      16:      }
    
      17:   
    
      18:      public void Dispose()
    
      19:      {
    
      20:          // Remove [this] from the thread context
    
      21:          CallContext.FreeNamedDataSlot("DoodleCounterScope");
    
      22:      }
    
      23:  }
    

    Finally let's add the counter property that's being incremented on line 18 of our example above.

       1:  [Serializable]
    
       2:  public class DoodleCounterScope : IDisposable, ILogicalThreadAffinative
    
       3:  {
    
       4:      public static DoodleCounterScope Current
    
       5:      {
    
       6:          get
    
       7:          {
    
       8:              return CallContext.LogicalGetData("DoodleCounterScope") as DoodleCounterScope;
    
       9:          }
    
      10:      }
    
      11:   
    
      12:      public DoodleCounterScope()
    
      13:      {
    
      14:          // Put [this] on the thread context
    
      15:          CallContext.LogicalSetData("DoodleCounterScope", this);
    
      16:      }
    
      17:   
    
      18:      /// <summary>
    
      19:      /// Gets or sets the total amount of times the Doodle method was called during the existence of this Scope
    
      20:      /// </summary>
    
      21:      public int Count { get; set; }
    
      22:   
    
      23:      public void Dispose()
    
      24:      {
    
      25:          // Remove [this] from the thread context
    
      26:          CallContext.FreeNamedDataSlot("DoodleCounterScope");
    
      27:      }
    
      28:  }
    

    Basic Scope Class Complete

    We have successfully created a basic scope class that puts a reference of itself onto the thread, has a static property to get a reference of that scope off the thread later in execution, and a property of which we can modify and retrieve later. 

    Tags:

    Categories:

    Comments

    8/31/2008 5:48:52 PM #

    Brent VanderMeide

    There also is an automated way of creating a thread specific object by attributing the variable with a System.ThreadStatic attribute.  However; your variable must be static.

    Brent VanderMeide | Reply

    11/28/2009 2:03:14 PM #

    Paul Lethons

    This is such a great resource that you are putting up and you give it away for free. I love seeing websites that realize the value of providing a prime resource for free. I truly loved reading your post. Thanks!

    Paul Lethons | Reply

    12/8/2009 1:23:06 PM #

    web directory

    hello admin, I found your blog from google and read a few of your other posts.They are cool. Please keep it up!!!! sincerely, Bill.

    web directory | Reply

    12/12/2009 1:18:19 PM #

    Micheal Blooms

    I had fun understanding this post. I want to see more on this subject.. Thanks for writing this nice article.. In Any Case, I’m going to sign to your rss and I wish you write great articles again soon.

    Micheal Blooms | Reply

    12/26/2009 4:47:48 AM #

    watch avatar movie online

    Hi. this is kind of an "unconventional" question , but have other visitors asked you how get the menu bar to look like you've got it? I also have a blog and am really looking to alter around the theme, however am scared to death to mess with it for fear of the search engines punishing me. I am very new to all of this ...so i am just not positive exactly how to try to to it all yet. I'll just keep working on it one day at a time Smile Thanks for any help you can offer here.

    watch avatar movie online | Reply

    1/3/2010 2:14:19 AM #

    Computer Support

    Great site, exactly what I was looking for, I can't get your RSS feed to work right in google chrome though, is it on my end?

    Computer Support | Reply

    Add comment




      Country flag

    biuquote
    • Comment
    • Preview
    Loading