Skip to content

3.0

C# 3.0, released with .NET Framework 3.5 in November 2007, introduced a number of significant features that built upon the capabilities of C# 2.0, enhancing the language's expressiveness, readability, and efficiency, particularly in data manipulation and querying. Here's a look at some of the key features introduced in C# 3.0, with examples and comparisons to earlier versions:

1. Auto-Implemented Properties

C# 3.0 introduced auto-implemented properties, simplifying property declaration when no additional logic is required in the property accessors.

C# 3.0

public class Person {
    public string Name { get; set; }
}

C# < 3.0 In earlier versions, you had to define backing fields and explicitly implement the property get and set accessors.

public class Person {
    private string name;
    public string Name {
        get { return name; }
        set { name = value; }
    }
}

2. Implicitly Typed Local Variables (var)

The var keyword allows the compiler to infer the type of a local variable, making the code cleaner, especially when dealing with complex types.

C# 3.0

var numbers = new List<int>();  // The compiler infers that 'numbers' is a List<int>

C# < 3.0 Previously, you had to explicitly specify the type of the local variable.

List<int> numbers = new List<int>();

3. Object and Collection Initializers

Object and collection initializers allow you to create and initialize objects and collections in a more concise and readable way.

C# 3.0

var person = new Person { Name = "Alice" };
var numbers = new List<int> { 1, 2, 3 };

C# < 3.0 Before C# 3.0, you had to create the object or collection and then set properties or add items in separate statements.

Person person = new Person();
person.Name = "Alice";

List<int> numbers = new List<int>();
numbers.Add(1);
numbers.Add(2);
numbers.Add(3);

4. Anonymous Types

Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first.

C# 3.0

var product = new { Name = "Laptop", Price = 1200 };
Console.WriteLine(product.Name);  // Output: Laptop

C# < 3.0 Previously, to achieve similar functionality, you had to define a class or struct.

public class Product {
    public string Name { get; set; }
    public int Price { get; set; }
}

Product product = new Product { Name = "Laptop", Price = 1200 };

5. Extension Methods

Extension methods allow you to add new methods to existing types without modifying the original type, enhancing the usability of existing classes or interfaces.

C# 3.0

public static class StringExtensions {
    public static int WordCount(this string str) {
        return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
    }
}

string text = "Hello, world!";
Console.WriteLine(text.WordCount());  // Output: 2

C# < 3.0 Before extension methods, you typically had to create a utility class with static methods to achieve similar functionality.

public static class StringUtils {
    public static int WordCount(string str) {
        return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
    }
}

string text = "Hello, world!";
Console.WriteLine(StringUtils.WordCount(text));

6. Language Integrated Query (LINQ)

LINQ introduces query capabilities directly in C# syntax, allowing for more expressive and readable data querying and manipulation.

C# 3.0

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = from n in numbers
                  where n % 2 == 0
                  select n;

foreach (var n in evenNumbers) {
    Console.WriteLine(n);  // Output: 2 4
}

C# < 3.0 Prior to LINQ, querying and manipulating collections or data sources required more verbose and less intuitive code, often involving loops and conditional statements.

List<int> evenNumbers = new List<int>();
foreach (int n in numbers) {
    if (n % 2 == 0) {
        evenNumbers.Add(n);
    }
}

foreach (int n in evenNumbers) {
    Console.WriteLine(n);  // Output: 2 4
}