in

 

Ray Houston

May 2008 - Posts

  • Do Anonymous Methods Prevent Declaring Types from Being GC'd?

    It seems that they do if they reference members of the declaring type. This makes perfect sense now that I think about it, but I didn't think about it earlier and wrote some code that caused a memory leak. I had an object acting as a singleton and referencing a delegate instance that was created from an object acting as a non singleton. Bam! Memory Leak.

    I setup a little test to demonstrate. Here is a class that has two methods which return delegate instances:

    public class TestSource
    {
        private string internalValue = "test";
    
        public Func<bool> GetFunc1()
        {
            return () => 1 == 1;
        }
    
        public Func<string> GetFunc2()
        {
            return () => internalValue;
        }
    }
    

    Notice that GetFunc1() doesn't have any references to internal members, but GetFunc2() does. Here's the test class:

    class Program
    {
        static void Main(string[] args)
        {
            // hold no references to TestSource
            TestFuncInstance(new TestSource().GetFunc1());
            TestFuncInstance(new TestSource().GetFunc2());
    
            Console.WriteLine("Press Enter to continue.");
            Console.ReadLine();
        }
    
        private static void TestFuncInstance(Delegate func)
        {
            Thread.Sleep(1000);// give some time for GC
    
            Console.WriteLine(string.Format("Method: {0}",func.Method));
            Console.WriteLine(string.Format("DeclaringType: {0}", func.Method.DeclaringType));
            Console.WriteLine(string.Format("Target: {0}", func.Target ?? "null"));
    
            Console.WriteLine();
        }
    }
    

    This creates two separate instances of TestSource and passes the result of the two GetFunc methods to a test method. Notice that there are no declared variable references to the TestSource object. Here's the output of the test:

    Method: Boolean <GetFunc1>b__0()
    DeclaringType: TestingDelegates.TestSource
    Target: null 
    
    Method: System.String <GetFunc2>b__2()
    DeclaringType: TestingDelegates.TestSource
    Target: TestingDelegates.TestSource 
    
    Press Enter to continue.
    

    I know this test isn't very scientific, but you'll see that Func1's target is null while Func2's target is not. Func2 has to hold a reference to the declaring object so that it can do it's job when invoked. Func1 does not need a reference, and seems to free up the declaring object to be garbage collected. This is definitely something to keep in mind when passing around delegates.

    Technorati Tags: ,,
  • Synchronizing UI Operations with Asynchronous Dependencies

    When working with asynchronous data access such as using a Silverlight client to access data from a server side service, you will inevitably run into the situation where you have two or more calls which have results that need to be processed in a synchronous manner. A simple example is populating a list box from server side data and then making a second call to get the value that needs to be selected. You could wait until the list is populated before making the second call, but that would be a waste.

    I built a little helper object that allows you to define Action delegates that will get executed in a specific order once all pending operations have completed. Below is a snippet of how it can be used.

    private ILoginService loginService;
    private ILoginView loginView;
    private OperationSync localeOpSync = 
            new OperationSync(LocaleOps.GetLocales, LocaleOps.GetDefaultLocale);
    
    private void PopulateLocales()
    {
        loginService.GetLocales(HandleGetLocalesResult);
        loginService.GetDefaultLocale(HandleGetDefaultLocaleResult);
    }
    
    private void HandleGetDefaultLocaleResult(string result)
    {
        localeOpSync.OpCompleted(LocaleOps.GetDefaultLocale, GetSetSelectedLocaleAction(result));
    }
    
    private void HandleGetLocalesResult(string[] result)
    {
        localeOpSync.OpCompleted(LocaleOps.GetLocales, GetSetLocaleSelectionAction(result));
    }
    
    private Action GetSetSelectedLocaleAction(string result)
    {
        return () => loginView.SetSelectedLocale(result);
    }
    
    private Action GetSetLocaleSelectionAction(string[] result)
    {
        return ()=> loginView.SetLocaleSelections(result);
    }
     
    In this example, there are two asynchronous service methods which get called. Their results are passed to handler methods where they are processed by Actions, but those Actions don't execute until both OpComplete methods have fired (actually the last OpComplete triggers the execution of all the Actions. It doesn't matter which call returns first. Their associated Actions will execute in the order defined by the keys in the creation of the OperationSync object. There are a million different ways to put this together with lambdas and anonymous methods, but I tried to bust it up here so it would be easier to follow.

    To show how it works I've included a subset of the unit tests (with extension methods and other goodies stripped out). The setup for all the specs is at the bottom of the code snippet.

    [TestFixture]
    public class when_not_completing_all_ops 
        : behaves_like_setting_up_operation_actions
    {
        [Test]
        public void should_not_execute_actions()
        {
            OpSync.OpCompleted(OpKey.One, Action1);
            OpSync.OpCompleted(OpKey.Two, Action2);
    
            CollectionAssert.IsEmpty(ActionResults);
        }
    }
    
    [TestFixture]
    public class when_completing_all_ops_in_key_order 
        : behaves_like_setting_up_operation_actions
    {
        [Test]
        public void should_execute_actions_in_key_order()
        {
            OpSync.OpCompleted(OpKey.One, Action1);
            OpSync.OpCompleted(OpKey.Two, Action2);
            OpSync.OpCompleted(OpKey.Three, Action3);
    
            Assert_That_ActionResults_Fire_In_Correct_Order();
        }
    }
    
    [TestFixture]
    public class when_completing_all_ops_not_in_key_order 
        : behaves_like_setting_up_operation_actions
    {
        [Test]
        public void should_execute_actions_in_key_order()
        {
            OpSync.OpCompleted(OpKey.Two, Action2);
            OpSync.OpCompleted(OpKey.Three, Action3);
            OpSync.OpCompleted(OpKey.One, Action1);
    
            Assert_That_ActionResults_Fire_In_Correct_Order();
        }
    }
    
    public abstract class behaves_like_setting_up_operation_actions
    {
        protected OperationSync OpSync { get; set; }
        protected Action Action1 { get; set; }
        protected Action Action2 { get; set; }
        protected Action Action3 { get; set; }
        protected List<OpKey> ActionResults { get; set; }
    
        [SetUp]
        public void Before_Each_Spec()
        {
            OpSync = new OperationSync(OpKey.One, OpKey.Two, OpKey.Three);
    
            Action1 = () => ActionResults.Add(OpKey.One);
            Action2 = () => ActionResults.Add(OpKey.Two);
            Action3 = () => ActionResults.Add(OpKey.Three);
    
            ActionResults = new List<OpKey>();
        }
    
        protected void Assert_That_ActionResults_Fire_In_Correct_Order()
        {
            Assert.That(ActionResults.Count, Is.EqualTo(3));
            Assert.That(ActionResults[0], Is.EqualTo(OpKey.One));
            Assert.That(ActionResults[1], Is.EqualTo(OpKey.Two));
            Assert.That(ActionResults[2], Is.EqualTo(OpKey.Three));
        }
    
        protected enum OpKey
        {
            One,
            Two,
            Three
        }
    }
    

    The keys can be anything. I have just been creating a private enum in the class where I need them. Here's the OperationSync class that handles it all:

    public class OperationSync
    {
        private static readonly object syncRoot = new object();
    
        private readonly object[] keys;
        private readonly Dictionary<object, bool> keyKeepActionAfterExecute = 
            new Dictionary<object, bool>();
    
        private readonly Dictionary<object, Action> keyActions = 
            new Dictionary<object, Action>();
    
        public OperationSync(params object[] operationKeys)
        {
            keys = operationKeys;
    
            foreach (var o in operationKeys)
            {
                keyActions.Add(o, null);
            }
        }
    
        public void OpCompleted(object key, Action action)
        {
            OpCompleted(key, action, false);
        }
    
        public void OpCompleted(object key, Action action, bool keepActionAfterExecute)
        {
            lock (syncRoot)
            {
                if (!keyActions.ContainsKey(key))
                    throw new UIException("Key '{0}' not found.");
    
                keyActions[key] = action;
                keyKeepActionAfterExecute[key] = keepActionAfterExecute;
    
                if (AllOpsComplete())
                    ProcessActions();
            }
        }
    
        private void ProcessActions()
        {
            ExecuteEachAction();
    
            ClearActionsIfIndicated();
        }
    
        private void ExecuteEachAction()
        {
            foreach (var key in keys)
            {
                keyActions[key]();
            }
        }
    
        private void ClearActionsIfIndicated()
        {
            foreach (var key in keys)
            {
                if (!keyKeepActionAfterExecute[key])
                    keyActions[key] = null;
            }
        }
    
        private bool AllOpsComplete()
        {
            return keyActions.All(pair => pair.Value != null);
        }
    }
    

    There's probably a fancy smancy AJAX pattern name for this sort of thing. Let me know if you come across one.

    Technorati Tags: ,,,

  • Connecting ActiveRecord to SQL Server

    Disclaimer: I'm a Ruby noobie. I know nada about Rails. Please leave a comment if something is not correct or if there is a better way to do this.

    At work, we're using Watir to drive a Silverlight application for some automated end to end testing. We needed an easy way to access the database from our RSpec test fixtures to make sure the proper setup data is put where we need it. I discovered that ActiveRecord can be used without rails and that all I needed to do was just install the gem. Typing the following seemed to do the trick for me:

    gem install activerecord

    I then found this which told me that I have install the SQLServer adapter separately like so:

    gem install activerecord-sqlserver-adapter --source=http://gems.rubyonrails.org

    It then also says that one must get the latest source distribution of Ruby-DBI from here and copy the file:

    lib/dbd/ADO.rb

    to your Ruby installation directory in the following place:

    X:/ruby/lib/ruby/site_ruby/1.8/DBD/ADO/ADO.rb

    After that I was able to create a simple test page to see if could actually get connected.

    ActiveRecordTest.rb

    require 'active_record'
    
    ActiveRecord::Base.pluralize_table_names = false
    
    ActiveRecord::Base.establish_connection(
        :adapter => "sqlserver",
        :host => ".\\SQLEXPRESS",
        :database => "MyDB",
        :username => "sa",
        :password => "sa"
    )
    
    class Customer < ActiveRecord::Base
    end
    
    Customer.find(:all).each do |cust| puts cust.Name end

    This test selects all the customers and outputs their names.

    Technorati Tags: ,
Copyright Los Techies 2007. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems