The Least You Need to Know about C# 3.0

Jomo Fisher—A lot of people (myself included) have written about LINQ in the next version of C#. LINQ is indeed an empowering technology. However, even without LINQ, C# 3.0 would be a compelling upgrade. Now that Beta2 is publicly available, here’s my personal list of the most useful features in the next release:

You Can Target Older .NET Framework Versions

There are many reasons you might want your application to run on an older version of the frameworks. In Visual Studio 2005, this was very hard to accomplish. In Visual Studio 2008, there is now built-in support for this. Right-click on Project èPropertiesèApplication:

image

Once this is set, you’ll get a build error if you try to use a framework assembly from a more recent version. One critical thing here: all new C# 3.0 language features are available even if you’re targeting .NET 2.0 or 3.0. This means you will be able to use most new language features, but not LINQ itself because it requires supporting assemblies from the 3.5 framework.

Unfortunately, support wasn’t extended back to .NET Framework 1.1.

Automatic Properties

The automatic property feature is one of my favorite new features because it makes it easy create to immutable classes:

        class Point {

            public int X { get; private set; }

            public int Y { get; private set;}

            public Point(int x, int y) {

                X = x;

                Y = y;

            }

        }

Here, X and Y are true properties but the compiler is providing a hidden implementation of the backing field. This is a nice, succinct representation that allows you to modify the implementation of the properties if you need to later.

Simpler Delegates

I tend to use a lot of delegates while writing unittests because they can allow me to mock a function so that I can isolate a particular piece of code. In the 2.0 compiler, you would write a delegate like this:

 

Func<int, int> mydelegate = delegate(int x) { return x + 1; };

 

In C# 3.0, this can be simplified to:

 

Func<int, int> mydelegate = x => x + 1;

Going forward, the delegate keyword is still there for compatibility but there’s no reason to use it (except maybe if it seems more explicit to you). Notice also, that you don’t have to specify the type of ‘x’. In many cases, the compiler can figure out the type for you.

 

Type Inference: The var Keyword

You can now ask the compiler to try to figure out a type for you:

 

var name = "Bob";

The var keyword is not the same thing as object. The difference is that the compiler knows what the type of the variable name is. For example, this code will compile with no errors:

 

        public static int GetName() {

            var name = "Bob";

            return name.Length;

        }

 

If you replaced that var with object the code would not compile because there’s no Length method on the type object.

 

A possible downside is that when you’re reading through someone else’s code your brain has to do the type inference in order to understand what’s happening. To help with this, the editor gives you some help. Just hover your cursor over a particular var:

image

HashSet

The .NET framework finally has a built-in Set Collection. It’s called HashSet because Visual Basic has a Set keyword already.

 

Collection Initializers

There’s a new syntax for initializing collections:

 

var mystrings = new List<string> { "Alice", "Bob", "Charlie" };

 

The only requirement is that the collection type implements IEnumerable and the collection type has a suitable method called Add. The corresponding code in C# 2.0 is not terse:

 

List<string> mystrings = new List<string>();

mystrings.Add("Alice");

mystrings.Add("Bob");

mystrings.Add("Charlie");            

 

Extension Methods

Extension methods allow you to add methods to pre-existing types. This example adds a new method to the built-in string class.

     public static class MyStringMethods {
        public static string Reverse(this string s) {
            StringBuilder sb = new StringBuilder(s.Length);
            for (int i = s.Length - 1; i >= 0; --i) {
                sb.Append(s[i]);
            }
            return sb.ToString();
        }
    }

Unlike regular class methods, extension methods aren't allowed to access private and protected members of the class.

 

Expression Trees

I went back and forth about whether to include Expression Trees in this particular article. They’re not as simple to explain or understand as the rest of the stuff in this list. However, given that they’re probably the most important single feature I’m giving it a shot. Expression trees allow you to capture and manipulate the structure of a function at runtime. Consider this delegate that adds one to its input:

 

Func<int, int> myexpr = x => x + 1;

 

Now, a simple change allows you to get the function as an expression tree. Add Expression<> around the Func<int,int> like this:

 

Expression<Func<int, int>> myexpr = x => x + 1;

 

Now myexpr is a tree that represents the function. You can manipulate it, analyze it and compile it into a true delegate that you can execute. This powerful trick of making code and data the same thing is as old as LISP (which has been called the only computer language that is beautiful). That’s all I’m going to say here, but I do show some powerful ways to use this feature here and here.

 

Okay, that’s my list. I’ve excluded anonymous types because I haven’t found a truly compelling use for them separate from LINQ. If you have one I’d be very interested in hearing about it.

 

Honestly, the new 3.0 compiler has changed the way I work. So much so that I’m unhappy when I have to work on the VS 2005 machine I keep at home. I hope you’ll be as happy with C# 3.0 as I have been over the last year or so.

 

Update August-8, 2007--Here's another developer's perspective https://spellcoder.com/blogs/dodyg/archive/2007/08/08/7756.aspx that I found insightful.

 

This posting is provided "AS IS" with no warranties, and confers no rights.

 

kick it on DotNetKicks.com

Comments

  • Anonymous
    July 26, 2007
    You've been kicked (a good thing) - Trackback from DotNetKicks.com

  • Anonymous
    July 27, 2007
    Mark pointed out a mistake in the first section about multi-targetting. Indeed you can't query objects with LINQ against 2.0 because the extension attribute and extension methods are in System.Core.dll.

  • Anonymous
    July 27, 2007
    I really just thought there needed to be a clarification.  You can query objects, but only if they have the standard query operators defined directly on them.

  • Anonymous
    July 27, 2007
    You're right, but I don't think people will find it that useful because the basic collections (array, list, etc) won't have those methods defined. At one point, I believe you could define your own ExtensionAttribute outside of System.Core.dll but it looks like this isn't possible in beta2.

  • Anonymous
    July 30, 2007
    You mention the var keyword as being one of the features you consider most useful. Don't you think this makes code less readable? Yes, you can simply hover over a variable and obtain the type information you need but then that means while reading through code I need to continually keep hovering over the variables in order to truly understand the code. What does var really buy you, a few keystrokes? I'll take readability over a few more typed characters anyday.

  • Anonymous
    July 30, 2007
    The comment has been removed

  • Anonymous
    July 30, 2007
    Thanks for this. Very handy to know indeed! Expression trees are great!

  • Anonymous
    July 31, 2007
    vardoubter, var is crucial for LINQ. The results/type returned from a query is anonymous; var makes it easy to use the result of a LINQ query without having to know its type. If you didn't have var LINQ would be really painful.

  • Anonymous
    July 31, 2007
    Here's a great overview of the goodies we can look forward to http://blogs.msdn.com/jomo_fisher/archive/2007/07/23/the-least-you-need-to-know-about-c-3-0.asp

  • Anonymous
    July 31, 2007
    You can use linq in .net2, just copy System.Core.dll to your Bin or GAC

  • Anonymous
    August 12, 2007
    There are several good new blogs from members of the community team. Nevertheless, the most important

  • Anonymous
    August 12, 2007
    There are several good new blogs from members of the Microsoft C# team. Nevertheless, the most important

  • Anonymous
    August 13, 2007
    Check this post for anonymous Types http://www.vikramlakhotia.com/New_Anonymous_Types_in_C_sharp_30.aspx

  • Anonymous
    August 28, 2007
    As you can probably tell from the title of my last few posts I've been doing some work with LINQ over

  • Anonymous
    August 28, 2007
    As you can probably tell from the title of my last few posts I've been doing some work with LINQ over

  • Anonymous
    September 03, 2007
    As you can probably tell from the title of my last few posts I've been doing some work with LINQ over

  • Anonymous
    September 10, 2007
    So using the Target Framework option can one build the same project for mutiple frameworks just by chaning the framework, then build? Then make an installer?

  • Anonymous
    October 18, 2007
    Jomo Fisher--A few weeks ago, a fellow C# programmer asked me what the biggest differences between programming

  • Anonymous
    October 18, 2007
    Jomo Fisher--A few weeks ago, a fellow C# programmer asked me what the biggest differences between programming

  • Anonymous
    October 31, 2007
    I've revisited this recently, and discovered that you CAN indeed declare your own ExtensionAttribute in beta 2 and still use extension methods while targetting v2.0.  It just needs to be in the System.Runtime.CompilerServices namespace, and all will be happy.