Since its release, C# has travelled a long journey from being a imperative language to a declarative one. With this journey the way we use to write methods have also changed a lot. Lets try to understand the journey of a method from C# 1.0 to 6.0
This is how we use to write methods in C# 1.0 .These were called named methods.Also you can see how a delegate is using a named method to print a value to console.
class CSharp1
{
public delegate void MyDelegate(string name);
public void Hello()
{
Console.WriteLine("Hello");
//A delegate using a named method
MyDelegate mydelegate = new MyDelegate(Print);
mydelegate2("Shakti");
}
/// <summary>
/// Named Method
/// </summary>
/// <param name="name"></param>
private void Print(string name)
{
Console.WriteLine(name);
}
}
C# 2.0 Introduced Partial Methods as well as anonymous methods using delegate’s syntax
Partial Methods
partial class CSharp2
{
partial void Hello();
}
partial class CSharp2
{
partial void Hello()
{
Console.WriteLine("Hello");
}
}
Advantages:
1.) Allow developer working on same module to share contracts
2.) Partial methods are simply ignored by compiler if no concrete definitions are present, giving them a great place in template driven programming
Limitations:
1.) Can only be private and void.
Anonymous methods:
Till C# 2.0 we could only create named methods. While using delegates sometimes we require methods having just one line of code as shown in example above. No matter how short a method is, we still need to create that as a named method. Named methods are good if we are going to call them from multiple places but if we just need to call them from a delegate i.e. a single place, it’s kind of an overhead to create a named method. C# 2.0 introduces the concept of anonymous methods to be used in delegates.
public class CSharp2O
{
public delegate void MyDelegate(string name);
public void Hello()
{
Console.WriteLine("Hello");
//A delegate using a named method
MyDelegate mydelegate = new MyDelegate(Print);
mydelegate("Shakti");
//Delegate using anonymous method to achieve same functionality
MyDelegate mydelegate2 = new MyDelegate(delegate(string name) { Console.WriteLine(name); });
}
/// <summary>
/// Named Method
/// </summary>
/// <param name="name"></param>
private void Print(string name)
{
Console.WriteLine(name);
}
}
C# 2.0 also introduced 2 new delegates which changed the way we write methods.
public class CSharp2O
{
public delegate void MyDelegate(string name);
public Predicate<int> IsEven = delegate(int i)
{
return i%2==0;
};
public Action<string> PrintIt = delegate(string s)
{
Console.WriteLine(s);
};
}
C# 3.0 went step further ahead and introduced Lambda expressions. Let’s try to understand the journey of Lambda expression syntax using some examples:
public class CSharp3O
{
public delegate void MyDelegate(string name);
public void Hello()
{
Console.WriteLine("Hello");
//A delegate using a named method
MyDelegate mydelegate = new MyDelegate(Print);
//Delegate using anonymous method to achieve same functionality
MyDelegate mydelegate2 = new MyDelegate(delegate (string name)
{
Console.WriteLine(name);
});
//Lambda expression Step By Step.. Step 1
//As you see just removed delegate keyword from above and placed => symbol after parameters
MyDelegate mydelegate3 = new MyDelegate((string name)=>
{
Console.WriteLine(name);
});
//Lambda expression Step By Step.. Step 2
//Since type is inferred in delegates. We don't require type in parameter.Let's remove
MyDelegate mydelegate4 = new MyDelegate((name) =>
{
Console.WriteLine(name);
});
//Lambda expression Step By Step.. Step 3
//if its a single parameter we dont require paranthese around parameter
MyDelegate mydelegate5 = new MyDelegate(name =>
{
Console.WriteLine(name);
});
//Lambda expression Step By Step.. Step 4
//if its a single line we dont require curly braces around code and trailing semi colon.
//Curly braces are only required for multiline code
MyDelegate mydelegate6 = new MyDelegate(name => Console.WriteLine(name));
mydelegate2("Shakti");
}
C# 3.0 also introduces a new delegate called Func , the typical syntax is like Func<T,TResult>.Consider that last parameter in Func is the return type of method wehere as rest are input to method. Consider below examples:
public class CSharp3O
{
public delegate void MyDelegate(string name);
public Action<string> PrintIt = delegate(string s)
{
Console.WriteLine(s);
} ;
public Func<int, int> func = (i) => i * 5;
}
So what’s happening here? When we assign a lambda expression to a variable, we end up creating expression trees. Expression trees are powerful and in-memory representation of lambda expression data. This representation allows APIs to exchange information in intuitive way and paved way for transalation frameworks like LINQ to SQL.
We can create expression trees from delegates as well like below.
public class CSharp3O
{
public delegate void MyDelegate(string name);
public Action<string> PrintIt = delegate(string s)
{
Console.WriteLine(s);
} ;
public Func<int, int> func = (i) => i * 5;
public Expression<Func<int, int>> expression = (i) => i * 5;
}
In above code, expression variable hold the representation of data of lambda expression (i) => i * 5 . When we create expressions we only have representation and no executable code but expressions can easily be transformed(Compiled) to excutable code by calling
Func<int, int> func2 = expression.Compile();
Even after all these powerful features, there was one thing that was missing i.e. creating a method at class level without using delegates.
This feature has been added in C# 6.0 as below:
public class CSharp3O
{
//C# 1.0
public delegate void MyDelegate(string name);
//C# 2.0
public Action<string> PrintIt = delegate(string s)
{
Console.WriteLine(s);
} ;
//C# 3.0
public Func<int, int> func = (i) => i * 5;
public Expression<Func<int, int>> expression = (i) => i * 5;
//C# 6.0
public void PrintMe(string name) => Console.WriteLine(name);
}