Note: In order to take advantage of these features, Visual Studio 2008
is required. If you don’t already have a copy of VS2008, you can
download the free express version here.
As we know, .NET Framework 2.0 uses CLR version 2.0.
.NET 3.0 and 3.5 are also based on CLR 2.0 and adds some new features like WCF (3.0), WPF (3.0), LINQ (3.5).
To get a general idea of the difference and relationship between .NET 2.0, 3.0 and 3.5, please refer to:
In fact, .NET Framework 3.5 includes .NET Framework 2.0 SP1 and 3.0 SP1. .NET Framework 2.0 and 3.0 cannot be removed because they are the prerequisite of .NET Framework 3.5.
.NET 3.0 and 3.5 are also based on CLR 2.0 and adds some new features like WCF (3.0), WPF (3.0), LINQ (3.5).
To get a general idea of the difference and relationship between .NET 2.0, 3.0 and 3.5, please refer to:
In fact, .NET Framework 3.5 includes .NET Framework 2.0 SP1 and 3.0 SP1. .NET Framework 2.0 and 3.0 cannot be removed because they are the prerequisite of .NET Framework 3.5.
Automatic Properties
The first thing I’d like to talk about is a simple yet great feature
called "Automatic Properties." The basic idea is as follows: Typically,
when you want to have a public property on a class, you would have a
private variable at the class level, and then have a get/set property
for that variable:
12 private string firstName;
13
14 public string FirstName
15 {
16 get { return this.firstName; }
17 set { this.firstName = value; }
18 }
Nothing we haven’t done many many times. However, now, you can eliminate the private variable altogether, and just do this:
12 public string LastName { get; set; }
Yup, that’s it! The interesting thing here is that it’s really just compiler trickery. Behind the scenes, the compiler does create a backing field for you, and a full blown Property. Let’s look at the IL generated by the compiler for both of those properties:
As you can see, the compiler generated a private string for me, and called it k_BackingField. Very cool. Trust me, once you start using these, you’ll never look back!
There is one thing to point out though; when using Automatic Properties, your get and set methods can have no logic whatsoever. If you want to do any validation in your getter or for example raise an event in your setter, you’ll need to do it the regular way and create your own backing variable.
Implicitly Typed Local Variables/"var" keyword
Local variables can be given an inferred "type" of var instead of an explicit type. The var keyword instructs the compiler to infer the type of the variable from the expression on the right side of the initialization statement. The inferred type may be a built-in type, an anonymous type, a user-defined type, or a type defined in the .NET Framework class library.In simple terms, when declaring a local variable, you no longer need to specify what type of variable it is on the left hand side of the assignment call. For example:
int x = 10;
is just the same as this:
var y = 10;
It's important to note that this is NOT a dynamic type that's available in other languages like PHP or python. With dynamic types (which will be available in .NET 4.0) the compiler does NOT know at design time what Type the variable will be. It will be figured out at runtime. With C# type inference though, the compiler knows full well what the type will be. It can figure it out from what's on the right hand side. Now I know you're probably thinking "what's the point of this? how hard is it to just type a few extra letters?" Well, imagine if you have something like this:
Dictionary<string, List<StringBuilder>> dictionary = new Dictionary<string, List<StringBuilder>>();
Well don't you think it'd be neater if we had this?
var dictionary = new Dictionary<string, List<StringBuilder>>();
At first it may not seem like a big deal but you'll find yourself starting to use it quite often. The thing to point out though is that the "var" keyword can ONLY be used for variables that are local in scope. They can not be used for class level variables. This would NOT compile:
public class MyClass
{
var myVariable = new StringBuilder(); //compile error
public MyClass()
{
var varIable = new StringBuilder(); //this is fine
}
}
Object Initializers
Next up, is “Object Initializers.” Let’s create a simple class, we’ll call it Person. We’ll have three (Automatic) Properties. FirstName, LastName, and Age:
34 public class Person
35 {
36 public string FirstName { get; set; }
37 public string LastName { get; set; }
38 public int Age { get; set; }
39 }
Take note that this class has no constructor. Therefore, if I’d
want to instantiate a Person object and set all it’s values, I’d have to
do something like this:
27 Person alex = new Person();
28 alex.FirstName = "Alex";
29 alex.LastName = "Friedman";
30 alex.Age = 27;
27 Person alex = new Person
28 {
29 FirstName="Alex",
30 LastName="Friedman",
31 Age=27
32 };
You can set all properties this way, or only a select few that you want. Either way, it just saves you from having to type object. over and over again.
Intellisense makes it even easier for you. As soon as you open that first curly brace you get a list of all the available Properties you can set:
Collection Initializers.
Taking these Object Initializers one step further, there’s also a new
feature called “Collection Initializers.” Say you wanted to have a List with 3 Person objects. Here’s how you would normally do it:
27 List<Person> people = new List<Person>();
28 people.Add(new Person
29 {
30 FirstName = "Alex",
31 LastName = "Friedman",
32 Age = 27
33 });
34 people.Add(new Person
35 {
36 FirstName = "Jack",
37 LastName = "Bauer",
38 Age = 45
39 });
40 people.Add(new Person
41 {
42 FirstName = "Cloe",
43 LastName = "O'Brien",
44 Age = 35
45 });
46 //Yes, before anyone asks, I'm a big fan of 24 :)
Now, you can do all that in one line when instantiating the collection:
27 List<Person> people = new List<Person>
28 {
29 new Person { FirstName = "Alex",
30 LastName = "Friedman", Age = 27 },
31 new Person { FirstName = "Jack",
32 LastName = "Bauer", Age = 45 },
33 new Person { FirstName = "Cloe",
34 LastName = "O'Brien", Age = 35 }
35 };
Anonymous types
var o = new SomeType(); //local variable type SomeType o = new SomeType {SomeField=DateTime.Now, AnotherField=5.6}; // typeinitialisersWe can of course combine them:
var o = new SomeType {SomeField=DateTime.Now, AnotherField=5.6};
Extension Methods
The last topic I’d like to cover in this post (which is probably also
one of my personal favorites) is something called “Extension Methods.”
In short, extension methods allow you to add functionality to existing
classes. The best way to demonstrate, is by example. Very often, it’s
useful to be able to check a string if it’s all numeric. (For
validation, or whatever, doesn’t really matter). Extension methods now
allow you to “add” these methods on to the string class as if it were
part of the string class. Here’s how it’s done:
48 public static class StringExtensions
49 {
50 public static bool IsNumeric(this string s)
51 {
52 foreach (char c in s)
53 {
54 if (!char.IsDigit(c))
55 {
56 return false;
57 }
58 }
59 return true;
60 }
61 }
Simple method, just loop through the characters of the string, and if it’s not a digit return false, otherwise return true. (It doesn’t take into account $ signs and comas, but doesn’t really matter for this example). I’d like you to notice the syntax. When declaring an extension method, you use the “this” keyword in the method signature. Also, of note, extension methods MUST be declared in a static class, and MUST be static methods. Now here’s the cool part. Here’s how you’d use this method:
98 string number = "12345";
99 bool result = number.IsNumeric();
The thing to note about extension methods is that it's really just compiler trickery. The compiler basically takes the method call to the extension methods and turns it into something like this:
37 string number = "12345";
38 bool result = StringExtensions.IsNumeric(number);
I'll let you decide which way looks cooler and cleaner :)
One more thing about Extension Methods; here’s what it looks like in VS’s Intellisense:
That little blue arrow pointing down next to IsNumeric shows that this is an extension method.
Query Expressions
you can query the list of customers using query expressions:
List<Customer> listOfCustomers = new List<Customer> { { Id = 1, Name="Dave", City="Sarasota" }, { Id = 2, Name="John", City="Tampa" }, { Id = 3, Name="Abe", City="Miami" } };
var query = from c in listOfCustomers where c.City == "Sarasota" select new {c.Name,c.City};
Query Expression Translation
But, as I mentioned before, this is just a bit of syntatic sugar, because the query expression gets translated using Query Expression Translation
into extension methods that are invoked behind the scenes. The .Where
and .Select Methods are extension methods of IEnumerable<T>:
var query = listOfCustomers .Where(c => c.City.Equals("Sarasota")) .Select(c => new {c.Name, c.City});
Lambda Expressions
Lambda Expressions are shown above to ease the pain of typing the very verbose anonymous delegates:
c => c.City.Equals("Sarasota")
avoids
delegate(Customer c) { return c.City.Equals("Sarasota"); }
avoids
delegate(Customer c) { return c.City.Equals("Sarasota"); }
Extension Methods
As with all Extension Methods, they are sitting somewhere in a static class as static methods. In this case, System.Query.Sequence. The above can also be written as:
var query = Sequence .Where(listOfCustomers, c => c.City == "Sarasota") .Select(c =>new { c.Name, c.City });
Query Execution
And, of course, this query does not execute until it is enumerated:
var sarasotaCustomers = query.ToList();
No comments:
Post a Comment