RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


C# 3.0 Syntax Additions—Design Guidelines

These guidelines will help you understand new additions to C# 3.0 syntax and avoid some of the pitfalls you can encounter when using them.

# 3.0 includes a few syntactical additions to the language. For the most part, Microsoft added these language additions to support Language Integrated Query (LINQ). These features include (but are not limited to) lambda expressions, extension methods, anonymous types, implicitly typed local variables, automatic properties, and object initializers.

Most of the syntax additions fulfill very specific needs and should not reduce the importance of established coding and design methodologies and guidelines. When in doubt, prefer your established guidelines over the new syntax.

Microsoft's Anson Horton wrote a great article "The Evolution Of LINQ And Its Impact On The Design Of C#" that discusses LINQ's impact on the design of C# 3.0 and covers the new language features from a different perspective.

Lambda Expressions
You can think of lambda expressions as an evolution of C# 2.0's anonymous methods. Lambda methods are an attempt at bringing functional programming (a paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data) to C#.

Lambda expressions are based upon lambda calculus.

  • Prefer methods over lambda expressions when the same code is used repeatedly.
  • Prefer lambda expressions where anonymous delegates would have been appropriate in C# 2.0.
Extension Methods
Arguably one of the most controversial additions to C#, extension methods allow designers to "inject" static methods into any other class. Essentially extension methods are syntactic sugar for creating a static method that operates on the instance of a particular type. Before C# 3.0, you might write a general utility method like this:

   public static bool IsStringPlural(String text,
      CultureInfo cultureInfo)
   {/* ... */}
…and call it like this:

   String text = "languages";
   Boolean isPlural = 
        text, new CultureInfo("en"));
Extension methods have an innate ability to pollute your namespace, and currently there's no way to scope them.
The IsStringPlural method operates on a String object (ideally telling you that that word/phrase is plural for that given context). Extension methods allow you to associate a similar method to a class so you can call it as if it were a member of that class. For example, creating an IsPlural extension method for the String class doesn't change much from the original syntax of the IsStringPlural method declaration—it just adds a this keyword in the parameter list:

   public static bool IsPlural(this String text,
      CultureInfo cultureInfo)
   {/* ... */}
You'd call this extension method as follows:

   String text = "languages";
   Boolean isPlural = text.IsPlural(
      new CultureInfo("en"));
While this method call syntax is arguably easier to read, it also reduces discoverability—there's no way to tell from the line of code calling IsPlural that it really isn't a member of String or what class the method really is declared in.

Extension methods compile to ordinary static methods, and can be used as such:

   String text = "languages";
   Boolean isPlural = StringExtensions.IsPlural(text,
      new CultureInfo("en"));
Extension methods are intended to be used in association with lambda expressions to provide terse and vastly more readable query expressions.

The main drawback of extension methods is resolution. Essentially all extension methods are global; methods with the same name and same argument count cannot currently be differentiated. Therefore, extension methods have an innate ability to pollute your namespace; and there's currently no way to scope them. In other words, by simply adding a using statement to your file you can introduce compile errors.

  • Use extension methods sparingly.
  • Put extension methods in their own static class.
  • Consider grouping extension methods that extend a particular class into a single static class, and name that class "<ClassName>Extensions." If you do run into a name collision and are forced to use the static method call syntax, you don't want to end up with reduced readability.
  • Keep extension method classes in their own namespace to mitigate potential name collisions (if you run into a name collision you're forced back to using a static method call).
Editor's Note: This article was first published in the January/February 2008 issue of CoDe Magazine, and is reprinted here by permission.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date