Saturday, December 8, 2007

C# Type Inference But Still Strongly Typed

I have spent considerable time today reviewing Linq and more specifically Linq to Sql. I'm currently working on a blog post where I'll go in to the details of what I think the pros and cons of Linq to Sql are as well as my overall opinion. In case you couldn't guess it I'll be using NHibernate for my comparisons, after all it is what I'm familiar with.

While reviewing some things I ran in to the following compile time check. It was very simple for me to resolve, but I wonder if it will cause developers to fall in to traps. Especially those developers who have some experience with weakly typed languages such as Javascript.

Take a look at the following code I wrote:


AdventureWorksDataContext context =
new AdventureWorksDataContext();

var orders = from po in context.PurchaseOrderHeaders
select po;

if (chkUseDate.Checked)
{
orders = from po in orders
where po.OrderDate > dtOrderFrom.Value
select po;
}

orders = from po in orders
orderby po.OrderDate ascending
select new
{
po.PurchaseOrderID,
po.RevisionNumber,
po.OrderDate,
po.ShipDate
};


Does anyone see what is wrong with the code above and why it failed to compile?

The compile-time error was:
Cannot implicitly convert type 'System.Linq.IQueryable<AnonymousType#1>' to 'System.Linq.IQueryable<BLL.PurchaseOrderHeader>'. An explicit conversion exists (are you missing a cast?)

After seeing that I immediately realized that I tried to use an object which type inferred to return PurchaseOrderHeader objects to return anonymous type objects instead. You can't just change a reference to be of another type in C# 3.0, hence the strong typing, I should know better.

But honestly, with the whole var keyword, I wasn't really thinking about it. It was a minor slip up, but I wonder how many developers will fall in to that trap. I think some developers may have seen the var keyword before in Javascript and they may have used it in the fashion I just did.

That being said, I have been enjoying my time with Linq today. I should have a post up within the next few days with more details.

P.S. If you're wondering what is going on with the 3 step linq ueries above, that's how you write dynamic queries in Linq. Simply reference the previously defined query in your new linq query in order to further restrict the query which you are building. Keep in mind that writing a linq query doesn't perform any operations. You have to either enumerate over the values of the query or call a method on the query like ToArray(), ToDictionary(), Select() etc...

If you're curious how to resolve the issue above you just need to declare a new variable for the last query to store the new type. var results = <Linq expression> would work just fine.

--John Chapman

Solution Folders To Group Projects

While reading Scott Guthrie's blog today I stumbled upon one of his links of the day for december 8th entitled Big Solutions Can Be Organized Using Solution Folders which is at the .NET Tip of the Day web site.

Actually, this is really cool. Am I the only schmuck who didn't realize this was possible? I have used Solution Folders in the past, but it was always to group files which were not part of the actual build process. For example we always had a Libraries folder which contained the third party dlls which need to be referenced to build the project. This way all a developer needs to do to build the project is to download the latest source code, and the solution will automatically download the needed referenced assemblies. Plus any upgrade we do to a third party dll automatically propagates when someone gets latest.

But the ability to place projects within the folders to group them together? This will actually be very handy for us. At work our current solution has 33 projects, and truthfully it is growing! Being able to group the projects which are similar or somehow related will really come in handy for us.

Why didn't I realize this sooner?

--John Chapman

Testing For Collections

Where I work we developed some foundation classes to assist with our unit testing. We make heavy use of NHibernate on our product (We work one very large application) and wanted a way to ensure that we were not breaking our mapping files over time.

In order to accomplish this goal we developed a mechanism to manage multiple sessions and then compare object graphs between the two sessions. Basically we would call a creation method for the specified object type we are testing, assign all properties with random values, and then assign many-to-one associations using the child object's creation method.

The creation method has the option of automatically saving the constructed objects to an NHibernate session or not (these creation methods are also used for non NHibernate based tests).

After the object graph has been constructed we then flush the session, construct a new session and then load the same parent object view the new session. We then wrote a base method for our tests which compares the two objects to make sure they are identical.

Our comparison method uses reflection on objects which are being compared. We reflect over all properties and ensure they are all equal. When we reach a property which is not a simple type we recursively call our comparison method on that property to ensure all child properties of these objects are compared. To ensure there are no infinite loops we keep a collection of already verified objects to make sure we don't compare the same object twice.

The one catch here is that currently we ignore collections. Collections are far more difficult to test, especially because the majority of our collections are Sets. We can't simply check the number of positions in the collection and each position of the collection since every load of the object could result in a new order (Sets are not ordered after all).

During re-factoring we accidentally broke our comparison tests. While reading the below note that all collection properties of our business objects are interfaces which are later replaced with the appropriate collection implementation. The original implementer who checked to see if the property was a collection used the following code:


if (type.ToString().ToUpper().StartsWith("SYSTEM.COLLECTIONS")
|| type.ToString().ToUpper().StartsWith("IESI.COLLECTIONS"))


There are several things I don't like about that code. To be fair, the code actually worked for our implementations, but it is extremely dirty. There are several things wrong with this.

First, you shouldn't be checking for a type based on a name. Hard coding string based namespaces is unreliable and a bad idea. There is no way to get any sort of compile time checking from this.

Second, I'm typically opposed to ToUpper(), it's almost never what anyone wants, it's just been accepted from historical practices. People either do it because they don't want to think about what it should really be, or they do not know about using a CaseInsensitiveComparer.

Third, What if we chose to use a custom collection for one of our implementations? In that case it wouldn't actually have a name which matched either of those conditions.

So obviously I thought this needed to be re-factored. My attempt is shown below:

if (type is IEnumerable)

Seems really simple right? My thinking behind this was that every collection interface we use or have even known about has mandated that it also implement the IEnumerable interface. Take a look at all of your collection interfaces, no other interface is common between them. ICollection is not enforced by the generic interfaces. It may be enforced by the non-generic interfaces, but not the generic ones. As such I determined it wasn't safe to use ICollection.

Well, a co-worker of mine found out that I actually broke our mapping tests. Worse than that they were broken in a way where we would receive false positives. This simple change resulted in our mapping tests no longer testing strings. The System.String class is IEnumerable. This makes sense upon further inspection (enumerable list of characters). However, it was not something I first thought of.

So, the IEnumerable was bad, we have learned that. We could have checked for IEnumerable but not a String, but that seems dirty.

The sad thing here is that checking for ICollection actually works. Every single collection in the .NET 2.0+ framework and the Iesi.Collections package implements the ICollection interface, our problem with that is that it is not enforced by the interfaces we are using. Does anyone know why IList does not mandate ICollection? It mandates ICollection<T> and every implementation uses ICollection, so why not? It seems like it would have been beneficial to everyone. I have yet to find the drawback. After all, it does enforce IEnumerable.

My next attempt turned out to not actually work. I really was thinking this was the answer for us, but I didn't have my thinking cap on. My code can be found below. Note that the formatting is horrible, but needed to ensure that the blogger template does not cut off my code sample. Also note that obj in the example is the object which is being checked for a collection. Also note this is not a direct copy and paste, there are optimizations in our real code which are removed for simplicity here.

Type type = obj.GetType();
Type genericCollectionType = typeof(ICollection<>);

if (obj is ICollection
|| (type.IsGenericType
&& type.GetGenericArguments().Length
== genericCollectionType.GetGenericArguments().Length
&& genericCollectionType
.MakeGenericType(type.GetGenericArguments())
.IsAssignableFrom(type)
)
)


If you see here I check for ICollection first, and then if the item being tested does not match that interface I fall back on a generic collection test. Note that I compare the length of the generic arguments since attempting to MakeGenericType with the improper number of arguments would throw an exception.

This generic check works for collections like List<t>, Iesi.Collections.Generic.HashedSet<T> but it doesn't work for Dictionary<K,V>. Basically ICollection<T> has one generic type, but IDictionary<K,V> has two and therefore won't be tested. I would need to determine a way to see if it is assignable from ICollection<NameValuePair<K,V>> since that is how the Dictionary<> impelments ICollection<>.

I'm not sure the cleanest way to check for this. Plus, it won't actually be called since there doesn't exist a collection out there which doesn't implement ICollection.

So basically I'm jumping through a number of hoops which aren't totally needed, but I really wish the IList<> and IDictionary<> enforced ICollection<> then I would feel a whole lot more comfortable with this.

Does anyone know why they were left out? Is there a really good reason I am missing?

--John Chapman

Thursday, December 6, 2007

MS Unit Exception Testing

How do people handle exception expectations within the Microsoft unit testing framework built in to Visual Studio Team Edition? Of course there is the built in ExpectedExceptionAttribute where you mark the test itself with an exception which should be thrown while performing the unit test. If no exception is thrown it fails, if an exception of that type is thrown it passes, if the exception is of the wrong type it fails.

I don't know about others, but this rarely sits well with me. Typically when I write a test method I want the ability to test other conditions when an exception is thrown, or I want to use a single test method to test all exceptional cases within a single business object method. Do most people just write one test per case of a method? It seems like this would result in a lot of duplication of unit tests.

To address this issue I have historically used the following code:


[TestMethod]
public void TestSomeMethod()
{
try
{
SomeMethod();
Assert.Fail("Expected ExpectedException to be thrown "
+ "while calling SomeMethod.");
}
catch (ExpectedException) { }
}


Recently it occurred to me, why do I have to go through this process every time I want to test for exceptions. At first I was hopeful that an additional mechanism would be made available with Visual Studio 2008 MSUnit, but it was not. I then decided to investigating the ability to extend the framework.

Honestly, I feel a little dirty saying this, but this appears to be a good use case for Extension Methods. Yes, I know my previous statements regarding extension methods (C# 3.0 Extension Methods? A Good Idea?), but I honestly think this would be a good use of it.

Imagine writing the following code instead:

[TestMethod]
public void TestSomeMethod()
{
Assert.ThrowsException<ExpectedException>
(delegate { SomeMethod(); });
}


Wow, I really would enjoy that functionality if it was available to me. Unfortunately for me, I can not make this an extension methods. Extension methods are only allowed on instances of objects. Since Assert is a static class you can not add extension methods. So instead of using an extension method we are instead left with using our own custom static class for testing.

See the implementation of this below:

public static class CustomAssert
{
public delegate void MethodDelegate();

public static void ThrowsException<T>
(MethodDelegate method)
where T: Exception
{
ThrowsException<T>(method,
"Expected Exception of type "
+ typeof(T).ToString()
+ " was not thrown.");
}

public static void ThrowsException<T>
(MethodDelegate method,
string message)
where
T : Exception
{
try
{
method.DynamicInvoke();
Assert.Fail(message);
}
catch (T) { }
}
}


and now the final tests looks like:

[TestMethod]
public void TestMethod1()
{
CustomAssert.ThrowsException<ApplicationException>
(delegate { SomeMethod(); });
CustomAssert.ThrowsException<ApplicationException>
(delegate { SecondMethod(5); });
}
In all honesty when I first decided this was something I was interested in I thought extension methods would work for this. While writing the code for this blog I came to the realization that they wouldn't.

While researching how to make this approach work I did stumble across the xUnit.Net framework. It looks like the xUnit.Net framework already supports very similar functionality to what I am describing in this post. If you're interested with a unit testing framework with functionality like what I described maybe that is where you should look. If you want to stick to the existing Microsoft MS Unit framework, this may be a good approach to better handle your exception testing needs.

--John Chapman

Tuesday, December 4, 2007

DateTime.Now Precision Issues... Enter StopWatch!

I'm a little bit embarrassed by this one. Previously I bogged about DateTime.Now Precision, or the lack there of. I first discovered this phenomenon while performing my performance tests for my blog post NHibernate Access Performance, which showed the differences between property and field level access within NHibernate.

Basically I found that DateTime.Now was not very precise and worked horribly as a benchmarking tool to test relative performance. Well, now I've come to my senses and realized that the nail I was banging on was really a screw, and using the hammer wasn't really the best tool for the job. I've now come to learn of the screwdriver which answers my benchmarking needs. It turns out the System.Diagnostics.StopWatch class exists for just the purpose I was trying to use DateTime.Now for. DateTime.Now is not supposed to be accurate enough to be used for diagnostics.

The StopWatch class is very simple. To use it you basically construct an instance of the object, Call Start(), perform your operations and then call Stop(). The StopWatch will contain a property ElapsedTicks with the most accurate elapsed time available.

While I wish I knew about this before when I originally recorded the benchmarks, I know about it now, and I always say I enjoy learning new things. With this new found knowledge of the StopWatch class I decided to re-run my NHibernate Access Performance tests to see how they looked. The results were dramatically different than I found with the DateTime mechanism.

First, I re-ran the 100,000 accesses test with two threads running synchronously. This is meant to replace my original test I ran. These results can be seen below. Note that all times are in milliseconds.


I then decided to run these same tests again but this time in a synchronous manner, meaning that only one test would be running at any given time. These results can be seen below:


In truth, these last numbers are probably the most accurate representation of the true performance implications of using the various NHibernate access strategies.

Of interest though is that fact that my earlier tests for property level access were showing values of close to 600 ms for the basic property setter where as a simple switch to the StopWatch showed just 62 ms. There was a difference of a full order of magnitude? I was actually surprised by just how much these numbers varied. It turns out that the accuracy of DateTime.Now is even worse than I thought.

--John Chapman

Thursday, November 29, 2007

Where Is System.Collections.Collections.Generic.ISet?

.NET Framework 3.5 is released! Among the new enhancements? System.Collections.Generic.HashedSet (Reference: BCL Team Blog). Finally, proper Set semantics in the .NET language. Those of you who are familiar with NHibernate and the Iesi collections should be plenty familiar with Iesi.Collections.HashedSet and the other set based collections. Does this mean that NHibernate could finally be implemented with just the framework's collection structures?

It turns out no! Microsoft has chosen to not add an interface which matches this collections set based operations. There is no matching ISet interface which the new HashedSet implements. While some people will say "yeah but it still uses IEnumerable", I think this is a huge shortcoming of the .NET 3.5 framework. There is enough semantically different regarding a set than the other collections that it warranted its own interface to control how someone would interact with it.

The only thought I could come up with regarding why this obvious interface was left out is that if it is just an interface you can not guarantee that the collection behaves like a set. For example with a set you can not add the same item twice. If a custom collection were to implement said ISet and decided to let the Add method add the same item multiple times, what would stop them?

I suppose a set isn't something you can just define by an interface. Maybe I should let my emotions cool down prior to jumping over Microsoft for leaving out this interface. I guess I was just imagining the possibility of using NHibernate without having to add Iesi.Collections to my project. Then again, what would make me think that this would change, or change in a relevant time frame?

All that being said, I still wish they included the interface! After all there is an IDictionary which could theoretically be implemented in such a way that the custom collection could add the same key multiple times. If the Dictionary semantics can't be guaranteed by the already existing interface, then I say it would have been ok for such an interface to exist for the set.

--John Chapman

Tuesday, November 27, 2007

VSTS 2008 Web Test Forms Authentication

With the release of Visual Studio 2008 I was eager to test the Web Testing functionality to see if my issues from 2005 had been resolved. If you remember, Visual Studio 2005 did not support forms authentication with its web test functionality (see original post: Visual Studio 2005 Team Edition Web Test and the follow up VSTS Web Test Error Found).

Seeing as there is a hot fix for Visual Studio 2005 to resolve this issue, I figured the issue would be resolved with 2008. I figured this was finally my chance to make heavy use of the Web Test functionality. I opened up Visual Studio 2008 Team Suite and gave a simple web test a shot. No go! I receive the same exact errors I received with 2005.

How is this possible? How has such a blatant issue existed for over 2 years now? I know Microsoft is aware of it (based on the existence of the Knowledge Base article) so why hasn't someone resolved it for the release of 2008?

I'm very disappointed by this. So at this point I'm stuck looking for a work around. I'm still looking for suggestions if anyone has them.

Note that this is really a cookie problem and not a forms authentication issue. The cookie is sent to the client but never returned to the server. When I find a suitable workaround I'll post it here.

--John Chapman

Blogger Syntax Highliter