Monday, June 28, 2010

C# 4.0 Features

C# is a language we work on regularly, it is a language that we love the most. It is always good to see updates to such a lovely language which is very common to most of us. C# 4.0 after its release, comes with certain features that I think would love to know about. In this article I have discussed these common facts on C# 4.0 updates which you might find interesting.

Introduction


C# as a language is getting richer day by day whilst we are introduced with newer releases of .NET framework. Recently pronounced .NET 4.0 comes with lots of new features on different aspect of programming world. Some relates to technology, while some directly changes the basic API of the language structure. C# as a language is not deprived from those changes, and hence it is time to go on and understand few of the basic changes that are made in the C# language.

In this article, I will introduce the basic changes to C# 4.0. To start lets jot down the topics which I will discuss in this article first.

  1. Named and Optional Parameters
  2. Dynamic Keyword
  3. Co-Variance and Contra-Variance
  4. Event Object Locking Changed

These are not the only feature that is introduced with .NET 4.0. There are lots of others too. But to start with it, in this article I have talked about these heads. We will talk about others later on. Lets get started.




Named and Optional Parameters


C# didn't have Optional Parameters that VB.NET had for a long time. One who is coming from VB or VB.NET will definitely miss this feature. Lets start with Optional Parameter first. See the code :

Namespace NamedParameter

    Public Class OptionalParameterDemo

        Public Function MyFunctionWithOptionalParameter(ByVal x As String, Optional ByVal y As Integer = 10) As String
            Return String.Format(x, y)
        End Function

        Sub MyCall()
            Me.MyFunctionWithOptionalParameter("Will take optional parameter as {0}")
        End Sub
    End Class

End Namespace

n the above code, the call to MyFunctionWithOptionalParameter will return "Will take optional parameter as 10" as we have the second parameter y made as optional. Now if we want similar functionality in C# we need to write like this :

public string MyFunctionWithoutOptionalParameter(string x, int y)
{
     return string.Format(x, y);
}
public string MyFunctionWithoutOptionalParameter(string x)
{
     return string.Format(x, 10);
}

Therefore you can see we have actually created an overload which automatically places 10 for us in C#, which is actually unnecessary in most of the cases. Therefore you can say C# was having less flexibility than VB.NET.

Again if you see the IL of the above VB.NET method you will see :

.method public instance string MyFunctionWithOptionalParameter(string x, [opt] int32 y) cil managed
 {
    .param [2] = int32(10)
 }

So you can see, IL for the code also looks different. It is not actually an overload of method in VB.NET. Thus you can say, Optional parameter is already in the MSIL, but it is not exposed to C#.

C# 4.0 exposes this feature. In C# you can use Optional parameter as you can do in VB.NET for a long time.

Named parameters on the other hand lets you to specify parameters by Name. Many developers gets bored by knowing the exact sequence of parameter list. Sometimes one class takes string as first argument while another overload takes integer as first argument. Looking at such code is really horrendous. C# 4.0 introduces the new feature which lets you specify the name of the parameter while calling it using a colon (":"). Let us look how these two features looks like :

internal class NamedAndOptional
    {
        public string User{get;set;}
        public int Value1{get;set;}
        public NamedAndOptional(string user = "Blank", int val1 = 0)
        {
            this.User = user;
            this.Value1 = val1;
        }

        public float GetMultiple(int val1, int val2 = 2)
        {
            return val1 * val2;
        }
    }

You can see, I have used optional parameter to set User and Value1 in the default parameter. So while creating object of NamedAndOptional you will have :

NamedAndOptional opt = new NamedAndOptional();

opt = new NamedAndOptional("Raj");

//opt = new NamedAndOptional(10); //Throws error, as you cannot skip optional parameters

opt = new NamedAndOptional(val1: 10); // Runs fine with NamedParameter
opt = new NamedAndOptional("Raj", 10);

Thus with the one constructor you have eventually created all the 4 types of constructors. You should note that, you cannot skip optional parameter. If you want to do so, you need to use NamedParameter to specify the actual parameter name before you specify the argument.

public void CallMe(int mandatory, float optional1 = 3.5f, Guid optional2 = new Guid(), NamedAndOptional optional3 = null)
 {
       //Use of parameters 
 }

In the above method, you can see we have first parameter as mandatory and other 3 parameters as optional. You can call the method using either of the following :

CallMe(10);
CallMe(10, 5.0f);
CallMe(10, 5.0f, myguid);
CallMe(10, 5.0f, myguid, new NamedAndOptional());

//using Named Parameters
CallMe(mandatory:10, optional2: myguid, optional3: new NamedAndOptional());
CallMe(optional2:myguid, mandatory:10);

Rules for Named and Optional Parameters:

  • Optional Parameters must appear after all required Parameters. Thus in our case you cannot specify mandatory variable after any optional parameter.
    public void CallMe( float optional1 = 3.5f, int mandatory, Guid optional2 = new Guid(), NamedAndOptional optional3 = null) //This will not compile.
    {
           //Use of parameters 
    }
    
    The above code will not compile.
  • All optional parameters must be a compile time constants. Thus if you use:
    public void CallMe( float optional1 = 3.5f, int mandatory, Guid optional2 = new Guid(), NamedAndOptional optional3 = new NamedAndOptional()) //This will not compile.
    {
           //Use of parameters 
    }
    You cannot create an instance of a class in Default constructor.
  • You cannot skip any optional parameter without calling by their names. This I already discussed above.

Dynamic Keyword


After the introduction of "var" in C# 3.5, the use of anonymous types increased rapidly. But as C# doesn't truly supporting the dynamic types, which means the types will be determined during the runtime and any error that is produced will not affect compilation of the project, there were lots of limitations. var is determined during compile time, and it is implicitly typed variable so it cant be a return type of a method. dynamic on the other hand can be a part of return type or argument of a method and will act during runtime when actual object is set to it.

Let us look on the code below :



Here the dynamic object is created and a method is invoked. As this is truly dynamic, everything will be evaluated in runtime and hence you can call CallMe or even CallMe2(which is not present) during compile time and this will evaluated during runtime and produce errors.

Dynamic keyword is COM friendly, as everything is done during runtime using reflection, it can also handle com interfaces as and when passed to it.

Limitation


If you delve deep into what exactly happening on dynamics, as I wondered that compiler is actually not capable of creating true dynamic allocation, I saw this :

 So you can see the compiler is actually using Reflection to invoke the members for dynamic types. The dynamic type is actually assigned to a anonymous type and then the member is invoked. So if you assign a value type on a dynamic object it will box and unbox for you.

Co-Variance and Contra-Variance 


If you are coming from Mathematics or rather statistics, you must have already know the terms, co-variance and contra-variance. The co-variance means when one variable is changing another will also change accordingly. In case of Generics in C#, Variance exists but you cannot employ restriction of variance through the compiler.

Lets look into it using few examples :
public interface IPlanet
    {
        string Name { get; }
        
    }

    public class Earth : IPlanet
    {
        public int NosofContinent
        {
            get
            {
                return 7;
            }
        }
        #region IPlanet Members

        public string Name
        {
            get { return "Earth"; }
        }

        #endregion
    }
In the above code you can see I have created one Interface called IPlanet and one class derived from it called Earth. Now if I do :

public class Variance
    {
        public IPlanet GetObject()
        {
            return new Earth();
        }
        public IList GetList()
        {
            return new List();
        }
    }
Or in other words if I say :
IPlanet myplanet = new Earth();


does it mean

List myplanets = new List();


No, it isn't. The line will not compile and give you a nasty error message called :
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.IList'. An explicit conversion exists (are you missing a cast?)

Well, through this. if you do make an explicit cast, using :
List myplanets = (List)new List();


the error will be sorted out for time being, but eventually during runtime it will again throw this error. This is because of the fact List is not a List. This restriction is given to C# to ensure type safety.  How? Yes, say you have Mercury inherited from IPlanet. Now if you want List can be assigned to List, you can easily add a Mercury to the List of earth. Thus it violates type safety. Does it have a solution? Yes, C# 4.0 has a solution. With the introduction of Co-variance keyword out, you can restrict a collection to have only read permission to the collection. So this ensures that when you assign a List to a List you cannot insert an object of Mercury to it simply by dereferencing at a position.

So based on our motto we declare :


Now using C# 4.0 we can create the similar thing. Let us look the new version :

public interface IMyList where T:IPlanet
    {
        T this[int index]
        {
               get;
        }
    }

    public class MyList : IMyList
    {
        public List planets = new List();

        #region IMyList Members

        public IPlanet this[int index]
        {
            get 
            {
                return planets[index];
            }
        }

        #endregion
    }

The generic type parameter for the interface IMyList gets an out T parameter where T is restricted to IPlanet. That means the interface IMyList is instructed to generate any types under the IPlanet family and IPlanet can only appear in output position of the class IMyList. So if you now want to add a Mercury object to IMyList the compiler will apply coercive conversion of Mercury to Earth, and hence it will not allow this. Hence, it solves the problem of type safety and thus allows co-variance.

Thus our code runs fine now using :
public class Variance
    {
        public IPlanet GetObject()
        {
            return new Earth();
        }
        public IMyList GetList()
        {
            return new MyList();
        }
    } 

On the contrary, Contra-Variance is just an opposite to Co-variance. Contra-variance enables you to create interfaces or delegates where the Types can only come in input parameters, such as argument to a method etc. To make it clear, let us make it simple using IComparer which is actually redefined in C# 4.0 to have contra-variance.

public class LengthComparer : IComparer
    {

        #region IComparer Members

        public int Compare(IPlanet x, IPlanet y)
        {
            return x.Name.Length - y.Name.Length;
        }

        #endregion
    }
Now if you write,
myEarthlist.Sort(new LengthComparer()); //where mylist is a list of Earth
It will give a nasty error in less than C# 4.0 like :
cannot convert from 'DemoApp.Class1.LengthComparer' to 'System.Collections.Generic.IComparer'
In C# 4.0, the IComparer is restricted to only contain variables in input positions and hence it allows to compare list of earth with the same class as LengthComparer.
Contra-variance restrict the class to create object, rather it can only compare two objects passed into it. As it cannot create objects, type safety is guaranteed and it means you cannot have two objects as Mercury and Earth.

So in a nut shell, if you specify for an interface, you can only have T in output position. If you want to send T as argument of any method you will get an error. So if I write :
  public void Add(T planet)

        {

           

        }

in MyList I will get an error. Same in case of where the compiler will only allow to input T, it wont allow you to return T in output position.

Event Object Locking


If you know what happens when you try to add an EventHandler or try to remove one event handler from an Event Accessor or even a public event you might know, the compiler places an explicit object lock when the event are added or removed. This is something like lock(this).

It is always better to avoid lock(this) as say you are using multiple threads accessing same object. If you invoke lock(this) it means the object will be locked to all other threads even though another thread tries to access another portion of the code.  In case of C# less than 4.0, the compiler invokes explicit lock on the object when you want to add or remove a EventHandler from code. So it will look like:

private event EventHandler _myevent;
 public event EventHandler MyEvent
 {
     add { lock (this) { this._myevent += value; } }
     remove { lock (this) { this._myevent -= value; } }
 }

Now if you see the event accessor for the event you will see _myevent accessor is almost similar to what i wrote for MyEvent accessor.

 MethodImpl(MethodImplOptions.Synchronized)] attribute makes the object locked whenever the call to add event or remove event is made. This looks worse.

C# 4.0 cures this problem by introducing new Event modifications. Now if you compile the same code in C# 4.0 you will see,





 So in this case the event accessor will use Interlocked mechanism to lock on the event and remove all the handlers. Thus the object is not locked anymore. Thank god.


Conclusion


C# 4.0 comes with lots of features. In this article I have introduced you few basic new features. I hope you like reading this post. Feel free to write your comment. Thanks for reading.

3 comments:

  1. Please don't publish your website link here. This is not the place for advertisement. Please comment on post that I give.

    ReplyDelete
  2. Really very nice article.Very easy to follow.
    Can u give me more features about C# 4 ?
    I am eager to learn even some more .
    My email id sakthivel.pj@rediffmail.com

    ReplyDelete
  3. @shakthi

    Follow my blog, I have posted a number of posts in C# 4.0 here

    ReplyDelete

Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.

Author's new book

Abhishek authored one of the best selling book of .NET. It covers ASP.NET, WPF, Windows 8, Threading, Memory Management, Internals, Visual Studio, HTML5, JQuery and many more...
Grab it now !!!