Scott Hanselman

Improving LINQ Code Smell with Explicit and Implicit Conversion Operators

August 31, 2007 Comment on this post [9] Posted in Learning .NET | LINQ | Microsoft | Programming | XML
Sponsored By

It's fairly easy to learn a language - programming language or human language - and get to the point where you can be understood. Your intent may not be crystal-clear, but at least it can be figured out but the computer/listener. However, it takes time and consultations with "native speakers" to get to be really fluent and start writing poetry.

ScottGu has a fine sample on how to make a Simple Web-Based RSS Reader with LINQ to XML. In it he's filling an ASP.NET ListView using RSS XML as the data source. He makes a query like this to populate a collection of posts.

var posts = from item in rssFeed.Descendants("item")
    select new
    {   
        Title = item.Element("title").Value,
        Published = DateTime.Parse(item.Element("pubDate").Value),
        NumComments = Convert.ToInt32(item.Element(slashNamespace + "comments").Value,
        Url = item.Element("link").Value,
        Tags = (from category in item.Elements("category")
                orderby category.Value
                select category.Value).ToList() 
}

Seems pretty straight forward. He's grabbing a number of things from the <item> tag in the RSS and putting them into an anonymous type. See how he's using "select new" rather than "select new Foo"? My code smell doesn't like the .Values, but I'm not that worried yet.

I added my own feed and ran his code and got a NullReferenceException on this line. Remember it's all one line, so that can be confusing. It was hard to tell which of these expressions was telling me something was null. I guessed though, that it was the line looking for <rss:comments> on the blog post. DasBlog, the engine I use, doesn't include a <comments> element when there's zero comments. Perhaps it's right, perhaps not, regardless, it doesn't include. So, for DasBlog, zero comments means no <comments> element. This code doesn't handle that because the call to item.Element(slashNamespace + "comments").Value is a NullReferenceException as item.Element(slashNamespace + "comments") is null.

So, how do I say "make NumComments = the value of <comments> unless it's null, then make it zero?" First, we tried this.

NumComments = Convert.ToInt32(item.Element(slashNamespace + "comments") != null ? item.Element(slashNamespace + "comments").Value : "0")

The use of ? :, as in <expression> ? true : false is very comment in early C#. Wordy, but it works. Of course, we're indexing twice into item.Element, once to see if it's null and again to get the value it if it's not.

This didn't smell right to me, but a few things smelled bad both here and before. I don't like seeing all the .Value properties. Also, the Convert.ToInt32 seemed dodgy. I kind of felt like I shouldn't have to do that, or that I should called XmlConvert, rather than Convert.

I also felt that I should be able to use the ?? operator, as in x = y ?? z, meaning make x = y if y's not null, else x = z. But that darned .Value property gets in the way.

A few newish C# things can make it cleaner (Thanks Anders).

Explicit vs. Implicit Conversions

Classes can use the explicit or implicit keywords to control how types are converted. You use implicit if you can guarantee that no data will be lost in the conversion and you use explicit if you can't guarantee that. Implicit conversions are like long foo = bar, where bar is an int. Ryan Olshan has some good examples like:

public static implicit operator int(MyClass myClass)
{
    return myClass.Value;
}

Then later, you'd do something like int x = someMyClassInstance and the conversion is implicit.

Back to the LINQ to XML RSS, example there's a whole pile (24, actually) of explicit conversion operators defined for the XElement class. Here's the one for int? (Nullable int):

public static explicit operator int?(XElement element)
{
    if (element == null)
    {
        return null;
    }
    return new int?(XmlConvert.ToInt32(element.Value));
}

See how it calls .Value for me? It does exactly what I want. Also, because it'll return null, now I can do this (changes in red):

var posts = from item in rssFeed.Descendants("item")
    select new 
    {   
        Title = (string)item.Element("title"),
        Published = (DateTime)item.Element("pubDate"),
        NumComments = (int?)item.Element(slashNamespace + "comments") ?? 0,
        Url = (string)item.Element("link"),
        Tags = (from category in item.Elements("category")
                orderby category.Value
                select category.Value).ToList()
    };

I changed a few calls to .Value to explicit string casts to emphasize the point since the explicit operator for string is just this. Same with DateTime where the call to Parse becomes a cast.

public static explicit operator string(XElement element)
{
    if (element == null)
    {
        return null;
    }
    return element.Value;
}

Now before you go off on how this can be used for evil. Yes, of course it can. However, there's a very unambiguous expectation presented with explicit and implicit. You only get to use them as a class designer if you can promise they will work as expected.

In this case, I think it makes the code much cleaner. Here's the before and after again:

BEFORE:

var posts = from item in rssFeed.Descendants("item")
    select new
    {   
        Title = item.Element("title").Value,
        Published = DateTime.Parse(item.Element("pubDate").Value),
        NumComments = Convert.ToInt32(item.Element(slashNamespace + "comments") != null ? item.Element(slashNamespace + "comments").Value : "0"),
        Url = item.Element("link").Value,
        Tags = (from category in item.Elements("category")
                orderby category.Value
                select category.Value).ToList()     
    };

AFTER:

var posts = from item in rssFeed.Descendants("item")
    select new 
    {   
        Title = (string)item.Element("title"),
        Published = (DateTime)item.Element("pubDate"),
        NumComments = (int?)item.Element(slashNamespace + "comments") ?? 0,
        Url = (string)item.Element("link"),
        Tags = (from category in item.Elements("category")
                orderby category.Value
                select category.Value).ToList()
    };

Now NumComments will handle missing <comments> elements and things look tidier. Very cool. Thanks ScottGu and Anders for their help, direct and indirect.

It's going to take a while but a new, more refined sense of smell is in my future, I think. One doesn't have to necessarily remember that ?? and conversion operators exist, but rather to have a better "sense" when reading/writing code that there ought to be a cleaner way and then go looking for it.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Fixing Instance Failure when connecting to SQL Server 2005 Express

August 31, 2007 Comment on this post [8] Posted in ASP.NET | Learning .NET | Programming
Sponsored By

I was getting Instance Failure when connecting to my SQL Server Express 2005 Database in my C# ASP.NET application.  Very weird.

Instance failure. - Windows Internet Explorer

<connectionStrings>
    <add name="NorthwindConnString" 
connectionString="Data Source=.\\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True"
providerName="System.Data.SqlClient"/> </connectionStrings>

Trial and error just taught me that the problem was "Data Source=.\\SQLEXPRESS;" - It's the double \\. That's an escape sequence in C#. Everything worked when I switched the connection string to .\SQLEXPRESS.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

The VB equivalent to C# typeof() keyword

August 31, 2007 Comment on this post [12] Posted in Learning .NET
Sponsored By

This post is so I can search my blog for it later. For whatever reason I always forget this and find myself trying to remember what...

typeof(Foo)

...is in VB...it's...

GetType(Foo)

Sigh. Now I won't forget. I wish I know why that one always flummoxes me.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

5:01 Developers, Family, and Excitement about the Craft

August 30, 2007 Comment on this post [36] Posted in Learning .NET | Musings | Programming
Sponsored By

Ramesh Sringeri has a great post about the 5:01 developer. He heard the term from Paul Lockwood who used it in a talk recently.

Paul mentioned the frustrations of working with 501 developers. That was the first time I had heard the term 501 developer. A 501 developer is one who bolts out the door at 1 minute past 5pm. They are "outta here".

I like to think I came up with this term, although who knows anymore on the web? It was probably invented in the 1940s. ;) I knew a guy who said he invented "Location, Location, Location" but he was insane. Anyway...

Ramesh says:

There is never an end to stuff that can be done at work. But I got to stop at some point and "get on with life"....But of late, I am getting tired of coding yet another list box

I posted a comment on Ramesh's blog that I'll continue here.

When I started using the term 5:01 developer I wasn't trying to imply that time spent at work equaled commitment or productivity...although, that's a pretty weak statement from me considering that the term uses time to make its point. ;) It's not a very good term, I think.

What I was railing against by using the term was the person whose enthusiasm turns off at 5:01pm. I have to pick up my son also. I take him to school every day...and that's the way it should be. There's nothing wrong with leaving work on time. I certainly can't code until 4am either, my old hands won't take it. Hell, I code while wearing braces on both hands now.

I'm just saying that I prefer working with folks who are enthusiastic about the craft. Folks whose brains - whose excitement about problem solving - don't turn off at 5:01pm. I use the term 5:01 developer to refer to someone who is just at work to turn the crank. They're not necessarily creating new kinds of cranks or making new innovative crank designs.

I totally agree that coding another list box is a thankless job and I hope I don't have to do one again. I think that the "water level" (or the number of layers of leaky abstractions, if you like) is rising, and we as developers need to make sure our metaphorical boats are going to float with it.

That's why I'm so excited about technologies like LINQ and Ruby on Rails. They are making getting work done faster, easier. That's one of the reasons why I went to work for Microsoft, so I could help developers to get more done, faster...and, ironically, go home at 5:01 to be with their families.

Someone recently posted a comment on my post about Sharpening The Saw that surprised me:

Do you actually make *any* time for your family? There is more to life than work you know.

It was signed "The Unmotivated Masses." Clearly this guy/gal doesn't know me otherwise they'd know that Family Is The Whole Point.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

The Weekly Source Code 3

August 29, 2007 Comment on this post [10] Posted in Source Code
Sponsored By

In my new ongoing quest to read source code to be a better developer, I now present the third in an infinite number of a weekly series called "The Weekly Source Code." Here's some source I'm reading this week that I enjoyed.

  • Paint.NET - It's not just the world's shiniest free .NET paint program, but it's also 140,000 lines of yummy (and very well factored (in parts)) source code. It's all here. A plugin model, COM interop, a Command Dispatcher, crazy WinForms stuff, multi-platform support and even TabletPC usage. You can get the source from SkyOrb.
  • CoPilot.com - This is one of my favorite tools for connecting to a family member's PC when they are in trouble. Plus, it's an extension of VNC which is GPLed, so they make the source available for both Mac and Windows. Reminds me I'm happy to not be coding in C/C++ anymore.
  • JobObjectWrapper - I don't know why, but I love wrapper classes. I just like seeing really clean .NET wrappers to really horrible Win32 APIs. It's like watching a car crash for me; I can't look away. This is a simple API abstraction over the Win32 Job Object.
  • World of Solitaire - This isn't Open Source, but since it's AJAX/JavaScript goodness we can explore it. It's insane. Created by Robert at CosmicRealms, it's a brilliant and amazing piece of cross-browser DHTML.
  • Url Reservation Modifier - I wish utilities like this were built in. This is a GUI and a Library (separation is always nice) to modify URL Reservations in Http.sys (on systems that support it). This lets you hook up System.Net.HttpListeners as a limited user.

Feel free to send me links to cool source that you find hasn't been given a good read.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.