What Is New in C# 3.0 - Part 0 (Introduction for Java Developers)
It is high time I made my first IT post. This website was built as my first project with .NET 3.5 so it seems like it is appropriate to start with a series of articles about the new stuff in .NET 3.5. Part 0 is a (not so) short introduction to the features of C# 2.0 that are important for understanding the new features in C# 3.0. This way the following articles will be interesting and meaningful for people with Java or C++ but no C# background.
The first thing we will take a look at are the properties. The properties should be known to people with Delphi background but no equivalent is present in Java or C++. So we have a class and want to expose some of its fields. The two most common methods are making the fields public and creating accessors for them.
class Mlass
{
public string mring;
}
or
class Mlass
{
private string mring;
public string getMring()
{
return mring;
}
public void setMring(string arg)
{
mring = arg;
}
}
Almost all developers know that they ALWAYS have to wrap accessors around their public fields but a great deal of them do not know WHY they have to do that. What is the difference between these two pieces of code? Right now there is no difference. However sometimes you have to make a read-only property where you only have get method. You can also have a value that is calculated and does not have an underlying private field. However a question remains - Why should we always do it and not only when we need accessors. One obvious reason is that if you decide to add accessors later on you will have to rewrite the client code to call getMring() instead of just access the mring field. We will see later that this is no problem with C#'s properties but there is still a reason we should ALWAYS wrap properties around fields.
Here is how properties look like in C# :
class Mlass
{
private string mring;
public string Mring
{
get { return mring; }
set { mring = value; }
}
}
And the client code can call properties the same way it calls fields:
Console.WriteLine(mlass.Mring);
And also set them:
mlass.Mring = "some mring";
Properties are just accessors that syntactically look like a field to the client code. The body of the get part is executed whenever the property is accessed. It must return a value of the type of the property. It represents the get method from our Java example. The set part is executed whenever an assignment operator is applied to the property. The word "value" is a C# keyword that represents whatever the right-hand side of the assignment was. It is always an object of the type of the property. This is our set method. You can also have get-only and set-only properties. Everything is checked at compile-time so trying to assign a get-only property will result in compile-time error.
The fact that properties look like fields gives us some cool benefits like using the +=, *=, ++, --, etc. assignment operators. Imagine that we want to append "!" to the end of our mring. The Java version would look like this:
mlass.setMring(mlass.getMring() + "!");
C# version:
mlass.Mring += "!";
These two examples are 100% equivalent. The get part of the Mring property will still be called in C# just like getMring() is called in Java. You can also apply different access modifiers to the get and set parts. So you can have private set and public get. And why do we have to wrap properties around our fields if syntactically it is all the same? Syntactically properties may look like fields and you will not have to change the client code if you make a field a property but still we have defined a contract and if we are deploying an assembly the client code will expect fields and the compiled assembly will provide properties (which are just methods under the hood). That is why we have to be ready with the contract from the very beginning. That applies for Java style accessors the same way.
So that was the easy part. The second feature of C# that is very important for the new features in C# 3.0 are the delegates. They are the object-oriented, type-safe, managed version of C/C++ function pointers. Delegates are especially useful in event-driven scenarios when you need to call a method when some event is fired. Events in C# are represented with delegates and you can attach methods directly to them. Java's event handling requires implementing observer pattern as a workaround for the lack of a language mechanism to pass a method as an argument. IDEs usually generate the observer pattern implementation but the Adapter class is still there and you cannot get rid of it.
Delegates in C# are special classes declared like this:
public delegate string Melegate(String s);
You can then create an instance of the newly created type like this:
Melegate melegate = new Melegate(ActualMethod);
Delegates have signature with parameter list and return type just like methods. The signature defines what kind of methods the delegate can point to. In our example the delegate points to methods that accept one string argument and return a string. ActualMethod in this example is the name of a method that matches the signature of the delegate. You can call the delegate (i.e. call ActualMethod) like this:
Console.WriteLine(melegate("mring"));
That will call ActualMethod and return its result. A delegate with return type void can point to a number of methods. Especially useful if you want to attach more than one method to be called from an event as events do not expect a result to be returned. Delegates come with predefined operators for adding and removing methods from the list of methods like this:
button1.Click += new EventHandler(ActualMethod);
Where EventHandler is a delegate that has a return type void and ActualMethod is a method that matches EventHandler's signature. There is much more on events including the “event” access modifier, the convention for events and many more but our goal is to get ready for the new features in C# 3.0 so we do not care about events but will look at anonymous methods instead.
Anonymous methods (or anonymous delegates) are delegates that do not point to a named method which we have defined somewhere but instead introduce directly the code they point to. The syntax looks like this:
button1.Click += delegate { MessageBox.Show("I am an anonymous method"); };
You can specify a parameter list for an anonymous method but if you do not the compiler will figure it out from the signature of the delegate Click which we are assigning to. The same goes for the return type. In this example we just reduced the code bloat a bit by not writing an almost empty method that would be used only with the Click event. This is good but the real power of anonymous delegates is that the code in their body has full access to the scope they are in. Imagine that in the previous example the form that the button belongs to also has a label named lbl1 and a field called count of type int. We could write something like this:
button1.Click += delegate { lbl1.Text = "The button has been pressed " + ++count + "times"; };
That will increment the count field and set the text of the label. Neither the label nor the count field are in the delegate's parameter list. This technique comes from functional programming languages. The function(the body of the delegate in our case) is called "closure". The anonymous methods are very important for implementing the new stuff in C# 3.0.
There is just one more thing that we need for our C# 3.0 series and these are the partial classes. A partial class has the keyword partial in its declaration and this allows the declaration to be split in multiple files. The compiler just merges the files. This is very helpful when half of your class is generated by a tool and you want to add the other half. Looks like this:
public partial class Mlass
{
...
}
Provided that you had experience with C#, Java or C++ you should have understood this long introduction and if you have you should be able to understand what is coming in the following parts of the series.
Last edited by:
Stilgar
on
00:24 07.02.2008