Nigel Morse

Anonymous delegates rock

Published Tuesday, March 18, 2008 6:33 PM

I'm finding I really like C#'s anonymous delegates. I've used them several times now in various ways. Normal delegates are already a Good Thing, however basically they are C(++) function pointers with a much nicer syntax. Anonymous delegates do clever things like having the ability to access local variables.  This just provides some syntactic sugar and the compiler under the hood creates classes to hold the variables and puts the anonymous method on that class.  Take a look with a decompiler and you can see what gets generated.

One "obvious" pattern I've seen people here come up with independently is to invoke something on a worker thread from a UI thread, or the other way round (and sometimes both by nesting one delegate inside another).

However another use I like is what I want to share today.

I've been using WMI a bit recently. WMI can be used (amongst other things) to get information about remote computers.  I won't go into the detail here - there's plenty on the web about it (http://en.wikipedia.org/wiki/Windows_Management_Instrumentation).  I may even do a blog myself on it one day.

To access WMI via .NET you use the System.Management namespace.  There are various ways to call and get the information, but a common example is to run a query in a SQL-esque way - e.g. "select TotalPhysicalMemory  from Win32_ComputerSystem" will get you the total physical memory on a machine.  However to run a query like this requires quite verbose code, not least because a lot of objects you create need Dispose()ing of afterwards.


ManagementScope scope 
= new ManagementScope"\\\\mymachinename\\root\\cimv2" );
scope.Connect();
objQry = new ObjectQuery"select TotalPhysicalMemory from Win32_ComputerSystem" );
UInt64 totalMemory 0;
usingManagementObjectSearcher searcher = new ManagementObjectSearcherscope
{
    
usingManagementObjectCollection collection searcher.Get() )
    
{
        
foreachManagementObject obj in collection )
        
{
            totalMemory 
(UInt64)obj["TotalMemory"];
            
obj.Dispose();
        
}
    }
}

So great - i've got that out, but I want to find out how much free disk it has as well.  This query is "select Name,FreeSpace from Win32_LogicalDisk where DriveType=3" and could well return me more than one disk. (DriveType=3 means physical disks on this machine as opposed to mapped network drives etc.)

I can reuse the scope so the extra code is...

objQry = new ObjectQuery"select Name,FreeSpace from Win32_LogicalDisk where DriveType=3" );
Dictionary<string,UInt64drives = new Dictionary<string,UInt64>();
usingManagementObjectSearcher searcher = new ManagementObjectSearcherscope
{
    
usingManagementObjectCollection collection searcher.Get() )
    
{
        
foreachManagementObject obj in collection )
        
{
            drives.add
( (string)obj["Name"], (UInt64)obj["FreeSpace"] );
            
obj.Dispose();
        
}
    }
}

But that instantly offends me - I have 13 lines of code, of which 10 are the same as above.  That's 10 lines repeated whenever I want to run another query.

Instead I can define a method like this:

private delegate void UseManagementObjectManagementObject obj );

private static void DoWmiQueryManagementScope scopestring qryUseManagementObject callback )
{
    ObjectQuery objQry 
= new ObjectQueryqry );            
    
usingManagementObjectSearcher searcher = new ManagementObjectSearcherscopeobjQry ) )
    
{
        
usingManagementObjectCollection collection searcher.Get() )
        
{
            
foreachManagementObject obj in collection )
            
{
                callback
obj );
                
obj.Dispose();
            
}
        }
    }
}


Now I can reduce my 2 previous pieces to this:

ManagementScope scope = new ManagementScope"\\\\mymachinename\\root\\cimv2" );
scope.Connect();
UInt64 totalMemory 0;
DoWMiQueryscope"select TotalPhysicalMemory from Win32_ComputerSystem"delegateManagementObject obj )
                   
{
                       totalMemory 
(UInt64)obj["TotalMemory"];
                   
);

Dictionary<string,UInt64drives = new Dictionary<string,UInt64>();
DoWMiQueryscope"select Name,FreeSpace from Win32_LogicalDisk where DriveType=3"delegateManagementObject obj )
                   
{
                       drives.add
( (string)obj["Name"], (UInt64)obj["FreeSpace"] );
                   
);

Jobs a good'un :)

You need to sign in to comment on this blog

















<March 2008>
SuMoTuWeThFrSa
2425262728291
2345678
9101112131415
16171819202122
23242526272829
303112345
Investigating SQL Server 2008 Wait Events with XEVENTS
 Some reasons for the slow-running of database applications aren't obvious. Occasionally, even the... Read more...

Controlling Email Messages using Exchange's Transport Rules
 Some tasks that should have been easy in previous versions of Exchange just weren't. Now, with... Read more...

Software Tool design: The Three Rs
 To understand the full extent of the requirements of your users when you are redesigning a software... Read more...

JSON and other data serialization languages
 The easiest way to speed up an Ajax application is to take out the 'X' and use JSON rather than XML. Of... Read more...

Embedding Help so it will be used
 It is not good enough to make assumptions about the way that users go about getting help when they use... Read more...