Thursday, March 7, 2013

Static State!

GC.AddMemoryPressure(1000000); is not the safest line of code. You would not want to run it over and over again in a loop. Chapter 20 of C# 4.0 in a Nutshell by Ben and Joseph Albahari is on security and touches on a way to prevent this line of code from being run more than once. The example used static state which nearly gave me a nose bleed. I could not believe this sort of thing existed. Look at this:

namespace MvcApplication.Objects
{
   public static class GoofyThing
   {
      private static bool isUsedBefore;
      
      public static int DoSomethingGoofy(int value)
      {
         int goofyValue = value*7;
         if (!isUsedBefore)
         {
            goofyValue = goofyValue*7;
            isUsedBefore = true;
         }
         return goofyValue;
      }
   }
}

 
 

Yes, we will be able to set that private field even with the word static sprinkled everywhere. There is no way to make an instance of this class so instead when we set the private field it will be set application-wide for anyone (any caller) who uses the class. Given how the class is written the first number handed to it will be multiplied by seven and then multiplied by seven again, but then going forward that behavior will never happen again because the private field has been set. Instead every time our DoSomethingGoofy method is called after the first time, the number handed to it will merely be multiplied by seven once. I know this example is... goofy. A practical application is to use something like this to prevent memory manipulations from being called too often.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcApplication.Objects;
namespace UnitTestProject
{
   [TestClass]
   public class UnitTest
   {
      [TestMethod]
      public void TestMethod()
      {
         Assert.AreEqual(GoofyThing.DoSomethingGoofy(1), 49);
         Assert.AreEqual(GoofyThing.DoSomethingGoofy(2), 14);
         Assert.AreEqual(GoofyThing.DoSomethingGoofy(3), 21);
      }
   }
}

 
 

Crazy! I would have thought this sort of thing impossible. Maybe I've just never seen it before for good reason. My brain hurts!

Consider this refactoring to our test class. TheOtherMethod will fail as a test if run by itself (196 is expected in that circumstance) but succeed as a test if run after TestMethod!

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcApplication.Objects;
namespace UnitTestProject
{
   [TestClass]
   public class UnitTest
   {
      [TestMethod]
      public void TestMethod()
      {
         Assert.AreEqual(GoofyThing.DoSomethingGoofy(1), 49);
         Assert.AreEqual(GoofyThing.DoSomethingGoofy(2), 14);
         Assert.AreEqual(GoofyThing.DoSomethingGoofy(3), 21);
      }
      
      [TestMethod]
      public void TheOtherMethod()
      {
         Assert.AreEqual(GoofyThing.DoSomethingGoofy(4), 28);
      }
   }
}

No comments:

Post a Comment