C# is intended to be simple, modern, general-purpose, type safe, object-oriented programming language. It is almost 10 years now since the start of C#, during this long period the language has evolved from stage to stage but before talking about the future of C#, it is always better to mention the evolution of C# during the past 10 years.
If you take a look to the below figure, you will notice the trends that shape the development of C#, in each version you will find a new powerful feature that differentiate each stage from the other:
The first version of C# [V 1.0] was concentrating on building CLR (Common Language Runtime) which is kind of process virtual machine that abstracts the developer from OS management level like memory management, Threading and Exception handling. Java was the leading programming language to handle VM since 1997. C# learned a lot from Java and Microsoft was trying to avoid all the pitfalls of Java.
Through the second version of C# [V 2.0], C# team was trying to finish all the work that could not be done in the first version, so they take the principle of STL (standard template library) from C++ and evaluated STL to be C# generics. By providing Generics, C# team completed their main target of having complete programming language then Microsoft seeks how to give C# a competitive edge among the other programming language.
In the third version of C# [V 3.0] Microsoft starts to enter the era of declarative programming and the dream of all developers to embed SQL like queries into programming language came true by introducing LINQ. LINQ is based on recursive programming using lambda calculus, Microsoft is the leading company in introducing such idea into programming languages and by doing that C# was moving from OOP (Object Oriented Programming) to AOP (Aspect Oriented Programming). I have a nice talk about LINQ foundation that you can find here.
The Upcoming version of C# [V 4.0] the team is trying to follow the trend of dynamic programming, In this version Microsoft introduces the DLR (Dynamic language runtime) that allows a dynamic type system to be shared by all languages utilizing the DLR services and Dynamic method dispatch in addition to Dynamic code generation.
In my opinion, C# is following a mix of the following programming trends:
- Declarative Programming: The idea behind declarative programming is to concentrate on what your code should do, rather than how your code goanna accomplish it. C# 3.0 introduced declarative programming through LINQ, in LINQ you describe at a very high level what kind of query you want (Projection, Filtering, Grouping, …) but you don’t say anything about how to do it, behind the scene a different things might happen depending on your query, for example if you run the query against in-memory collection then your query eventually will be transformed to some loops and recursive functions but if you run the same query against SQL Server then your query will be translated to SQL and will be executed not even on .Net but in another environment which is SQL Server; when you wrote this query you didn’t say how you want it to be executed. C# 3.0 applies declarative programming style and gives you the tools to write more declarative APIs like extension methods and lambda expressions.
- Dynamic Programming: This technique describes a class of high-level programming languages that execute at runtime many common behaviors that other languages might perform during compilation. LISP was the first dynamic programming language created in 1958, it was originally created as a practical mathematical notation for computer program, in contrast C# 3.0 is a static programming language in which everything is defined at compile time. For several decades there were wars between the two camps and C# Team thought that it would be fine to assemble some features from dynamic programming languages in order to narrow the gap between the two camps. C# 4.0 introduces the dynamic language runtime (DLR) on top of CLR to provide necessary tools for dynamic programming.
- Concurrent Programming: The concurrent code can be executed sequentially on a single processor by interleaving the execution steps of each computational process, or executed in parallel by assigning each computational process to one of a set of processors that may be close or distributed across a network. The main challenges in designing concurrent code are ensuring the correct sequencing of the interactions or communications between different computational processes, and coordinating access to resources that are shared among processes. PLINQ (Parallel LINQ) is one of the LINQ providers that allows LINQ queries to be executed on multiple cores but in my point of view C# team has much to do with concurrency as they are still at the beginning. One of the most effective frameworks to handle concurrent programming is the CCR framework (Concurrency Coordination Runtime); it is a part of Microsoft robotics studio which can be found here.
After discussing the evolution of C# during the past 10 years let’s now explore the most important feature of C# 4.0. The new version of C# focuses on dynamic programming, Microsoft presented the DLR (Dynamic Language Runtime) on top of CLR:
The DLR adds a set of services to the CLR for better supporting dynamic languages. These services include the following:
- Expression trees: The DLR uses expression trees to represent language semantics. For this purpose, the DLR has extended LINQ expression trees to include control flow, assignment, and other language-modeling nodes.
- Call site caching: dynamic call site is a place in the code where you perform an operation like a + b or a.b() on dynamic objects. The DLR caches the characteristics of a and b (usually the types of these objects) and information about the operation. If such an operation has been performed previously, the DLR retrieves all the necessary information from the cache for fast dispatch.
- Dynamic object interoperability: The DLR provides a set of classes and interfaces that represent dynamic objects and operations and can be used by language implementers and authors of dynamic libraries.
C# 4.0 introduces Dynamic Lookup that allows you a unified approach to invoking things dynamically. With dynamic lookup, when you have an object in your hand you do not need to worry about whether it comes from COM, IronPython, the HTML DOM or reflection; you just apply operations to it and leave it to the runtime to figure out what exactly those operations mean for that particular object.
This affords you enormous flexibility, and can greatly simplify your code, but it does come with a significant drawback: Static typing is not maintained for these operations. A dynamic object is assumed at compile time to support any operation, and only at runtime will you get an error if it wasn’t so. Oftentimes this will be no loss, because the object wouldn’t have a static type anyway, in other cases it is a tradeoff between brevity and safety.
C# 4.0 presents the following gear for dynamic programming:
- New Dynamic Data Type: C# 4.0 bring in a new static type called dynamic. Objects of type dynamic can do anything that will be resolved only at runtime. The following example shows the old style of dynamic method call:
public static IClientChannel Use(Type endpointType, string config, string address)
{
Type channelType = typeof(ChannelFactory<>).MakeGenericType(endpointType);
object factory = Activator.CreateInstance(channelType,config);
((ChannelFactory)factory).Endpoint.Address =new EndpointAddress(address);
return (IClientChannel)channelType.GetMethod("CreateChannel", new Type[] { }).Invoke(factory,new object[] {});
}
The above code snippet shows part of my enterprise service bus (ESB) by using WCF. It creates WCF client channel at runtime depending on the WCF contract type, as you can see that it uses reflection in order to create the channel. By using C# 4.0 dynamics the above code can be simplified like the following:
public static IClientChannel Use(Type endpointType, string config, string address)
{
dynamic factory = Activator.CreateInstance(typeof(ChannelFactory<>).MakeGenericType(endpointType),config);
return factory.CreateChannel(new EndpointAddress(address))as IClientChannel;
}
As you can see that the C# compiler allows you to call a method with any name and any arguments on factory because it is of type dynamic. At runtime the actual object that factory refers to will be examined to determine what to do. For high performance system like ESB; reflection will degrade overall performance but by using dynamic you will not hurt performance as the DLR will cache your dynamic calls and the next time you will do dynamic calls it will not use reflection but it will use the cache.
- Dynamic Operations: Dynamic objects allows you to ship dynamically method calls, field and property accesses, indexer and operator calls and delegate invocations:
dynamic d = new SomeDynamicObject();
d.ID = new Random().Next(1, 10000);
d.ClientName = "Hana Ahmed";
d.Balance = dummy * new Random().NextDouble();
d.Tax = (Func<double, double>)((double Precent) => { return d.Balance * Precent/100; });
The C# compiler will snatch the necessary information about your dynamic object so that the DLR can pick it up and determine what the actions to be done but you must know that the result of any dynamic operation is itself of type dynamic.
- Dynamic objects: These types of objects enable you to define which operations can be performed on dynamic objects and how to perform those operations. For example, you can define what happens when you try to get or set an object property, call a method, or perform standard mathematical operations such as addition and multiplication.
In order to define your own dynamic objects you will need to derive from a helper class called DynamicObject. If your class defines properties and also overrides the TrySetMember method, the dynamic language runtime (DLR) first uses the language binder to look for a static definition of a property in the class. If there is no such property, the DLR calls the TrySetMember method. Here is an example of dynamic object:
public class Order : DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name.ToLower();
return dictionary.TryGetValue(name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name.ToLower()] = value;
return true;
}
}
You can find the full source code that demonstrates all the dynamic code that we discussed here. CSharp4.zip (33.73 kb)
There are a few and things that might work differently than you would expect:
- Dynamic data objects cannot be used in inter-process communication which means that they only reside at your process level. Infrastructure communication code will not be able to serialize these objects between domains.
- The DLR allows objects to be created from objects that represent classes. However, the current implementation of C# doesn’t have syntax to support this.
- Dynamic lookup will not be able to find extension methods. Whether extension methods apply or not depends on the static context of the call (i.e. which using clauses occur), and this context information is not currently kept as part of the payload.
- Anonymous functions (i.e. lambda expressions) cannot appear as arguments to a dynamic method call. The compiler cannot bind (i.e. “understand”) an anonymous function without knowing what type it is converted to.
Currently rated 4.4 by 8 people
- Currently 4.375/5 Stars.
- 1
- 2
- 3
- 4
- 5