Posts
202
Comments
1112
Trackbacks
51
August 2007 Entries
C# 3.0 Extension Methods - Real World Example

C# 3.0 Lambda Expressions play an integral part of making the LINQ framework work.  Outside of LINQ it is recommended that they be used sparingly because they are less "discoverable."  However, there are a couple of nice scenarios where extension methods have good potential to make your code more elegant as a stand-alone language enhancement.

Take an example where you have a nullable value in the database and you represent this as a Nullable<DateTime> on your C# object (e.g., EmploymentEndDate).  When you go to save this value back to the database, you want to save a DateTime value (if one exists), otherwise you want to save a null to the database - specifically a DBNull.Value.  With C# 2.0 you'd have to write a static method like this:

public static object ToDBValue<T>(Nullable<T> nullable) where T : struct
{
    if (nullable.HasValue)
    {
        return nullable.Value;
    }
    else
    {
        return DBNull.Value;
    }
}

and call it like this (note the line below is EntLib rather than straight ADO.NET but that's immaterial to this example):

db.SetParameterValue(cmd, Params.EmplEndDate, DBUtil.ToDBValue(person.EmploymentEndDate));

With C# 3.0 you can convert the static method to an extension method by simply adding the this modifier to the first parameter like this:

public static object ToDBValue<T>(this Nullable<T> nullable) where T : struct
{
    if (nullable.HasValue)
    {
        return nullable.Value;
    }
    else
    {
        return DBNull.Value;
    }
}

Which allows you to call the method like this:

db.SetParameterValue(cmd, Params.EmplEndDate, person.EmploymentEndDate.ToDBValue());

This syntax is much more intuitive and concise.

 

Posted On Wednesday, August 29, 2007 9:26 PM | Comments (0)
C# 3.0 Lambda Expressions replacing Anonymous Methods

C# 3.0 Lambda Expressions play an integral part of making the LINQ framework work.  However, even apart from LINQ, they stand alone quite nicely as a great replacement to C# 2.0 anonymous methods in terms of language syntax usability.  For example, consider this simple anonymous method:

personList.RemoveAll(delegate(Person person)
{
    return person.DateOfBirth.Year < 1980;
});

While anonymous methods were a great language addition in C# 2.0, the syntax could be confusing at times in terms of getting the delegate signature correct and the curly braces all lined up in the right place.  In C# 3.0 this exact snippet of code can be re-written with Lambda expressions in a much more readable 1 line of code:

personList.RemoveAll(p => p.DateOfBirth.Year < 1980);

What's even more interesting here is that both snippets generate the EXACT same MSIL:

L_000f: ldsfld class [mscorlib]System.Predicate`1<class ConsoleApplication1.Person> ConsoleApplication1.Program::<>9__CachedAnonymousMethodDelegate2
L_0014: brtrue.s L_0029
L_0016: ldnull
L_0017: ldftn bool ConsoleApplication1.Program::<Main>b__0(class ConsoleApplication1.Person)
L_001d: newobj instance void [mscorlib]System.Predicate`1<class ConsoleApplication1.Person>::.ctor(object, native int)
L_0022: stsfld class [mscorlib]System.Predicate`1<class ConsoleApplication1.Person> ConsoleApplication1.Program::<>9__CachedAnonymousMethodDelegate2
L_0027: br.s L_0029
L_0029: ldsfld class [mscorlib]System.Predicate`1<class ConsoleApplication1.Person> ConsoleApplication1.Program::<>9__CachedAnonymousMethodDelegate2
L_002e: callvirt instance int32 [mscorlib]System.Collections.Generic.List`1<class ConsoleApplication1.Person>::RemoveAll(class [mscorlib]System.Predicate`1<!0>)

Notice the b__0 method - just like normal 2.0 anonymous methods the compiler is generating a hidden method behind the scenes to handle the delegate:

[CompilerGenerated]
private static bool <Main>b__0(Person person)
{
    return (person.DateOfBirth.Year < 0x7bc);
}

so I guess I just like the way the code becomes less verbose and easier to understand at the same time.  As an additional example, think about the ForEach<T>() anonymous method on the List<T> class in 2.0:

personList.ForEach(delegate(Person person)
{
    Console.WriteLine(person.ToString());
});

While nice, I always felt like it would just be a lot easier to write that statement like this:

foreach (Person person in personList)
{
    Console.WriteLine(person.ToString());
}

But now, with Lambda expressions, we finally have syntax that truly is more concise without losing readability:

personList.ForEach(p => Console.WriteLine(p.ToString()));

Posted On Wednesday, August 15, 2007 9:21 PM | Comments (2)
ConfigurationErrorsException - The configuration is read only.

The .NET 2.0 Configuration API is a huge step up from the previous versions of the framework rendering many other previous configuration framework (Enterprise Library Configuration block, etc.) virtually obsolete.  However, one thing that can trip people up is when they try to assign to a configuration property at run-time you can get a ConfigurationErrorsException - The configuration is read only even when a setter is defined on their property:

[ConfigurationProperty(item1Property, DefaultValue = 1, IsRequired=true)]
[IntegerValidator(MinValue=1, MaxValue=100)]
public int ConfigItem1
{
   get  { return Convert.ToInt32(this[item1Property]); }
   set  { this[item1Property] = value; }
}

The ConfigurationSection inherits from ConfigurationElement which defines a virtual method for IsReadOnly().  If you want to avoid this exception and actually assign your values at run-time simply override this method in your ConfigurationSection or ConfigurationElement class like this:

public override bool IsReadOnly()
{
    return false;
}

Posted On Tuesday, August 14, 2007 10:23 PM | Comments (14)
WinDbg real world example

I recently had to debug a problem for my current client which was exceptionally weird and I was able to utilize WinDbg to help get to the bottom of the problem relatively quickly.  Basically the application in question is an asp.net application that takes a custom object and puts in in an MSMQ message (which currently uses the default binary serializer).  The class in question is marked with the Serializable attribute, has a couple of primitive members (e.g., ints, strings) and a couple of NameValueCollections.  One of the NameValueCollections is assigned directly from the HttpRequest.Headers NameValueCollection like this:

myObject.Headers = request.Headers;

One day we started getting this error:

System.Runtime.Serialization.SerializationException: Type 'System.Web.HttpHeaderCollection' in Assembly 'System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' is not marked as serializable.

This made absolutely no sense since, like my class, the NameValueCollection class was also marked with the Serializable attribute.  Not only that, but where was the System.Web.HttpHeaderCollection coming from?

So since I was already debugging, I took a memory dump of the asp.net process from the command line like this:

cscript.exe adplus.vbs -hang -p 1808 -quiet -o c:\temp

The "1808" was simply the PID of my w3wp.exe process and I output the dump to the c:\temp directory.

I then launched WinDbg and opened the crash dump that was produced in the previous step. First, you have to run (the sos extensions is what allows WinDbg to understand .NET 2.0):

.loadby sos mscorwks

So the first thing I wanted to see was all the types in memory and their corresponding method tables so I ran:

!dumpheap -stat

A snippet of the results:

00000642802ae6c0        5          320 MyNamespace.Foo

(just using Foo here for the class name.  The real output included the fully qualified namespace with correct object name).  The 00000642802ae6c0 is the method table for my Foo object. The 5 shows that we currently have 5 of my Foo objects loaded into memory.  The 320 is the total size (320/5 tells me each of my objects is taking up 64 bytes).

Now I can narrow in on my issues a little bit. This shows me all 5 of the memory addresses for my Foo objects:

0:000> !dumpheap -mt 00000642802ae6c0
------------------------------
Heap 0
         Address               MT     Size
total 0 objects
------------------------------
Heap 1
         Address               MT     Size
00000000c0012e18 00000642802ae6c0       64    
total 1 objects
------------------------------
Heap 2
         Address               MT     Size
000000010053b830 00000642802ae6c0       64    
total 1 objects
------------------------------
Heap 3
         Address               MT     Size
0000000140235c60 00000642802ae6c0       64    
0000000140430fd8 00000642802ae6c0       64    
00000001405275d0 00000642802ae6c0       64    
total 3 objects
------------------------------
total 5 objects
Statistics:
              MT    Count    TotalSize Class Name
00000642802ae6c0        5          320 MyNamespace.Foo
Total 5 objects

So now I'm going to pick one of these five objects and drill down further.  I'll pick the one highlighted in blue that resides at 00000001405275d0:

0:000> !do 00000001405275d0
Name: MyNamespace.Foo
MethodTable: 00000642802ae6c0
EEClass: 00000642802baf08
Size: 64(0x40) bytes
 (C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\Temporary ASP.NET Files\root\e22c2559\92c7e946\assembly\dl3\fed41db4\000e24c3_21cac701\MyAssemblyName.DLL)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
0000000000000000  4000028        8                       0 instance 0000000140527610 requests
0000064274e85620  4000029       10 ...meValueCollection  0 instance 0000000140528d60 headers
0000064274e85620  400002a       18 ...meValueCollection  0 instance 0000000140527838 extraRequestData
0000000000000000  400002b       20                       0 instance 0000000140527a38 userStateData
000006427881edc8  400002c       28        System.String  0 instance 0000000000000000 endOfLineData
0000064278825318  400002d       30       System.Boolean  0 instance                0 isOptOut

So I know the "headers" member is the one I want for focus on so I inspect that next:

0:000> !do 0000000140528d60
Name: System.Web.HttpHeaderCollection
MethodTable: 00000642bcefad78
EEClass: 00000642bcf3be38
Size: 120(0x78) bytes
 (C:\WINDOWS\assembly\GAC_64\System.Web\2.0.0.0__b03f5f7f11d50a3a\System.Web.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
0000064278825318  4001165       44       System.Boolean  0 instance                1 _readOnly
00000642788426f0  4001166        8 ...ections.ArrayList  0 instance 0000000140528f78 _entriesArray
000006427881f650  4001167       10 ...IEqualityComparer  0 instance 00000000ffffc148 _keyComparer
00000642788448c8  4001168       18 ...ections.Hashtable  0 instance 0000000140529000 _entriesTable
0000064274e82360  4001169       20 ...e+NameObjectEntry  0 instance 0000000000000000 _nullKeyEntry
0000064274e9e7e8  400116a       28 ...se+KeysCollection  0 instance 00000001405481c0 _keys
0000064278857210  400116b       30 ...SerializationInfo  0 instance 0000000000000000 _serializationInfo
000006427882b338  400116c       40         System.Int32  0 instance               10 _version
000006427881d280  400116d       38        System.Object  0 instance 000000014054ad48 _syncRoot
000006427881f748  400116e      a70 ...em.StringComparer  0   shared           static defaultComparer
                                 >> Domain:Value  0000000000136900:NotInit  0000000000177700:00000000ffffc110 <<
00000642788d8ba8  4001179       48      System.Object[]  0 instance 0000000000000000 _all
00000642788d8ba8  400117a       50      System.Object[]  0 instance 0000000140548160 _allKeys
00000642bceef310  400101b       58 ...m.Web.HttpRequest  0 instance 00000001405265f0 _request
00000642bceef7b8  400101c       60 ....Web.HttpResponse  0 instance 0000000000000000 _response
00000642bcf3ad30  400101d       68 ...IIS7WorkerRequest  0 instance 0000000000000000 _wr

And NOW we see something extremely interesting.  The headers member was supposed to be a NameValueCollection so why is my !do showing it to be an HttpHeaderCollection and what is this HttpHeaderCollection anyway and how is this System.Web DLL even compiling? So at this point, it's time for us to crack open trusty old Reflector and find its class definition:

internal class HttpHeaderCollection : HttpValueCollection 

So this is an internal class to the System.Web DLL but it's being returned for a NameValueCollection property.  Also notice that it is NOT marked with the [Serializable] attribute (which was our problem to begin with).  It inherits from the HttpValueCollection (which is yet another internal class) and the HttpValueCollection (while it DOES have the Serializable attribute) inherits from the NameValueCollection object and THAT is how the code is compiling because of course this is a perfectly legal use of polymorphism.

So...in the end, all of these classes are marked with the Serializable attribute except for the HttpHeadersCollection (which I believe to have been an oversight on Microsoft's part) which is causing our serialization problems and we cannot control the internal code of System.Web.  The fix ends up being pretty trivial - just iterate the NameValueCollection and adds the string primitives so that all serialization is happy.

But the real moral of the story is that this is a good real world example that shows how to debug an issue that, at first glance, seems impossible. Using WinDbg like this is a very repeatable process that can help you get to the bottom of memory issues (and others) quite fast.

Posted On Tuesday, August 14, 2007 9:16 PM | Comments (0)
WinDbg / SOS Cheat sheet
This is a great post that anyone who works with WinDbg should check out:

http://geekswithblogs.net/.netonmymind/archive/2006/03/14/72262.aspx

Bookmark it - it will come in handy anytime you're debugging with WinDbg.
Posted On Tuesday, August 14, 2007 8:30 PM | Comments (0)

View Steve Michelotti's profile on LinkedIn

profile for Steve Michelotti at Stack Overflow, Q&A for professional and enthusiast programmers




Google My Blog

Tag Cloud