July 2009 - Posts

When Cast<T> doesn’t Cast to T

A friend asked me about some issues he was having using Enumerable.Cast<T>(). In his mind, it just wasn’t working. Like so many problems, it was working correctly, just not the way he expected. It’s worth examining.

Examine this class:

   1: public class MyType
   2: {
   3:     public String StringMember { get; set; }
   4:  
   5:     public static implicit operator String(MyType aString)
   6:     {
   7:         return aString.StringMember;
   8:     }
   9:  
  10:     public static implicit operator MyType(String aString)
  11:     {
  12:         return new MyType { StringMember = aString };
  13:     }
  14: }

Note:  I normally recommend against conversions, (See Item 28 in Effective C#), but that’s the key to this issue.

Consider this code (assume that GetSomeSttrings() returns a sequence of strings)

   1: var answer1 = GetSomeStrings().Cast<MyType>();
   2: try
   3: {
   4:     foreach (var v in answer1)
   5:         Console.WriteLine(v);
   6: }
   7: catch (InvalidCastException)
   8: {
   9:     Console.WriteLine("Cast Failed!");
  10: }

You’d expect that GetSomeStrings().Cast<MyType>() would correctly convert each string to a MyType usingthe implicit conversion operator defined in MyType. It doesn’t, it throws an InvalidCastException.

The above code is equivalent to this construct, using a query expression:

   1: var answer3 = from MyType v in GetSomeStrings()
   2:               select v;
   3: try
   4: {
   5:     foreach (var v in answer3)
   6:         Console.WriteLine(v);
   7: }
   8: catch (InvalidCastException)
   9: {
  10:     Console.WriteLine("Cast failed again");
  11: }

The type declaration on the range variable is converted to a call to Cast<MyType> by the compiler (See Item 36 in More Effective C#). Again, it throws an InvalidCastException.

Here’s one way to restructure the code so that it works:

   1: var answer2 = from v in GetSomeStrings()
   2:               select (MyType)v;
   3: foreach (var v in answer2)
   4:     Console.WriteLine(v);

What’s the difference? The two versions that don’t work use Cast<T>(), and the version that works includes the cast in the lambda used as the argument to Select().

And, that’s where the difference lies.

Cast<T>() Cannot access User Defined Conversions

When the compiler creates IL for Cast<T>, it can only assume the functionality in System.Object. System.Object does not contain any conversion methods, therefore, Cast<T>() does not generate any IL that might call any conversion operators.

Cast<T>() will only succeed if its argument is not derived from the target (or a type that implements the target if the target is an interface), Cast<T> fails.

On the other hand, placing the cast in the lambda for the Select clause enables the compiler to know about the conversion operators in the MyType class. That means in succeeds.

As I’ve pointed out before, I normally view Conversion operators as a code smell. On occasion, they are useful, but often they’ll cause more problems than they are worth. Here, without the conversion operators, no developer would be tempted to write the example code that didn’t work.

Of course, if I’m recommending not to use conversion operators, I should offer an alternative.  MyType already contains a read/write property to store the string property, so you can just remove the conversion operators and write either of these constructs:

   1: var answer4 = GetSomeStrings().Select(n => new MyType { StringMember = n });
   2: var answer5 = from v in GetSomeStrings()
   3:               select new MyType { StringMember = v };

Also, if you needed to, you could create a different constructor for MyType.

Will you thrive, or be left behind?

A few events recently uncovered a very interesting observation on how developers are hired: the business world often focuses developers toward the exact behavior it claims it doesn’t want. How many times have you heard recently that developers need to have ‘business skills’ and ‘understand the business problem’ and ‘talk to the business side of the house’. I agree that these are important skills for a modern professional developer. However, let’s look at the recruiting process for developers. How much of the developer recruiting process is focused on specific developer tool skills: years of Java, years of ASP.NET, C# and SQL experience, years working with Oracle, or whatever tool is needed in the job description. Really smart developers without those skills will lose out on an opportunity early in the screening process. That’s because they have the relevant business knowledge, and the relevant software construction knowledge, but not the latest buzzwords in the resumes.

Immediately, the law of unintended consequences starts to rear its ugly head because of this phenomena. Developers know this is how the recruiting project works. Their next job relies on their ability to gain relevant tooling experience with modern software construction tools. With that kind of motivation, it should not surprise any manager that her developers crave knowledge and experience with modern tools above any other relevant business experience.

In fact, I think that the business world gets the very developers they deserve. Companies that recruit based on buzzwords will get developers that intend to advance their careers by padding their resumes with buzzwords.  Companies that look for developers that can think, analyze problems, and deliver software that solves real problems will find those developers.

Aligning your skills to your goals

What kind of developer do you want to be?  And, equally important, what do you view as your contribution to your company? Is it a set of buzzwords or is it something greater?

One resource to help you find your way is Thrive, Microsoft’s new site for developers dedicated to advancing their career. This is a site with content from folks inside and outside Microsoft that have important advice and resources that can help you advance your career, even in the current economy.

There’s information on learning specific tech skills, growing your non-tech skills and helping to highlight them, and how to connect with your community. It’s certainly worth frequent visits.

And, remember to highlight the skills that make you most valuable.

Book Review: Essential LINQ

During my recent vacation, I read the final print version of Essential LINQ, by Charlie Calvert and Dinesh Kulkarni.

Normally, I try to answer the question, “Who should read this book?” That answer eluded me on this book, due to the thorough treatment Charlie and Dinesh give the subject. Essential LINQ is approachable by developers that have minimal experience with LINQ, and yet those developers that have been using LINQ since day one will learn something from this book.

The Essence of LINQ and LINQ Patterns and Practices

Everyone will learn something from two chapters in this book. “The Essence of LINQ” describes the principles behind the LINQ libraries and language enhancements. By understanding the goals of LINQ, you’ll immediately gain insight that will make LINQ more approachable and more productive for you.

In chapter 16, toward the end of book, Charlie and Dinesh discuss some patterns you’ll run into while developing with LINQ. You’ll learn how to use LINQ to SQL entities as part of a large multi-tier application. You’ll learn how to improve performance in LINQ applications. You’ll learn how to separate concerns in LINQ based applicaitons. LINQ is too new to be considered complete in terms of ‘best practices’, and thankfully neither Charlie nor Dinesh approach this subject with that kind of arrogance. Instead, they offer their recommendations, and invite discussion on the subject.

A catalog of LINQ Functionality

Throughout the rest of the book, Charlie and Dinesh explain LINQ to Objects and LINQ to SQL from a usage standpoint, and from an internal design standpoint. In other chapters, LINQ to XML is discussed. The authors provide examples of transforming data between XML and relational storage models as well. In every section, they tie together those features with the concepts discussed in “The Essence of LINQ”. That continuity helps to reinforce your understanding of LINQ through its design concepts.

After reading this book, you’ll be able to leverage LINQ in all your regular coding tasks. You’ll have a much better understanding of how LINQ works, and when you’ll encounter subtle differences in how different LINQ providers may behave.

LINQ to SQL vs. Entity Framework

It seems you can’t discuss LINQ without at least wading into the controversy of LINQ to SQL vs. Entity Framework. This book wades there as well (It was finished about the time the first EF release was made). More time is spent on LINQ to SQL, as it is more approachable from an internal design perspective. However, the chapters that cover EF build on that knowledge to help you understand how the two database LINQ technologies are more complementary adversarial. In addition, they touch on when you should consider one over the other in your application.

A look at providers

This section is the least complete, but the most useful to look into the future of the LINQ universe. It’s too easy to view LINQ as LINQ to Objects, LINQ to SQL, and LINQ to XML, and nothing more. This chapter gives you a brief view some of the other providers people have created for other types of data stores. Looking at some of those providers (especially the IQToolkit) will give you a greater appreciation for how LINQ can be used with a wider variety of data sources than you ever imagined.

So, is this book for you?

If you are interested in being more productive with LINQ, you should read this book. You’ll probably thumb through it again and again as you search for better ways to solve different problems.

Search

Go

Blog Group Links

Nascar style badges