Intro 15 years ago Microsoft presented its own vision of programming language. The name "C sharp" was inspired by musical notation where a sharp indicates that the written note should be made a semitone higher in pitch. Last year Microsoft presented new features in C# 6.0. Their goal was to simplify coding and they succeeded. Everyone knows null-conditional operator and auto-property initializer. Microsoft also improved new compiler performance. Today in 2015, The community tries again to improve the language and simplify the process of code writing. Now it is focused on cloud/data and performance/reliability. The list of features of C# 7.0 is being prepared and here one can have a look at them https://github.com/dotnet/roslyn/issues/2136 Once again community tries to extract benefits from existing paradigms and implement them within C#. In this article I’d like to show you how the language has developed in the dynamic direction and how to hide strongly typed language under wraps of syntactic sugar and features of C#. Ancient typed language
All you need is delegates.
C# 2.0 gives us many improvements. At that time language didn’t have such dynamics but reduction of code sizes was highly desirable, And here anonymous delegates came to the rescue. Delegates allowed to pass one function into another using the analog of the pointer. Good example is a calling function in a separate thread:
new System.Threading.Thread
(delegate(){
System.Console.WriteLine("Hello world!");
}).Start()
In C# 3.0 the feature of a functional language was implemented – lambda-expression. It simplified code significantly, The previously written snipped now looks far better**:**
new System.Threading.Thread(() => System.Console.WriteLine(“Hello world!”));
Most of all lambdas are used in method-based LINQ queries as arguments to standard query operator methods such as Where. They allow the Where calls to look similar nevertheless the type of object created from the lambda is different.
var intResult = intCollection.Where(x => x > 10);
var strResult = stringCollection.Where(x => x.Length > 10);
Reflection for the rescue
Want to see the devil, look at your reflection.
Next step in the development of dynamics in C# 3.0 was made towards reflection which has already showed itself successfully in Java. Reflection in C# gave great opportunities for obtaining information about the code in runtime.
MyClass inst = new MyClass();
PropertiesInfo[] ctor = inst.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
MethodInfo[] mthd = inst.GetType()
.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
In addition, it was possible to dynamically load individual assemblies for execution.
System.Reflection.Assembly myAssembly =
System.Reflection.Assembly.LoadFile("%MyDLLPath%\\MyDLL.dll");
System.Type MyDLLFormType = myAssembly.GetType("MyDLLNamespace.MyDLLForm<span style="line-height: 1.714285714; font-size: 8pt;">");
</span>
And most importantly it becomes possible to write new assembly in runtime.
The common steps to create your own dynamically created Assembly
Also, it was possible to create anonymous types. Anonymous types make it easy to encapsulate the read-only properties into a single object without having to determine the type first. Type name is created by the compiler and is not available on the source code level. The type of each property is established by the compiler. At the same time Microsoft started to add even more anonymity to C# - next step was implicit type which could be set to local variables. Keyword var allows the compiler know that it can determine type of variable from the expression located on the right side of operator initialization. Output type can be built-in, anonymous, user type or the type specified in the class library of the .NET Framework.
var result = from person in people
where person.Age > 18
select new { Name = person.Name, Age = person.Age } ;
or
var anon = new { Name = "Terry", Age = 34 };
Console.WriteLine(“{0} {1}”, anon.Name, anon.Age);
DLR
We need more supported language.
DLR architecture
https://msdn.microsoft.com/en-us/library/dd233052%28v=vs.110%29.aspx
С# 4.0 was marked by the release of DLR – Dynamic Language Runtime. It meant that we could use scripting language in .NET such as IronRuby and IronPython. Moreover it provided the source of DLR with which it became possible to create your own dynamic language for .NET, if you needed it.
static void Main() {
var ipy = Python.CreateRuntime();
dynamic test = ipy.UseFile("Test.py");
test.Simple();
}
DLR includes Expression Trees which are representation of method calls or binary operations in the form of a tree. Their functionality can be viewed at the following example:
Expression<Func<int, bool>> exprTree = num => num < 5;
// Decompose the expression tree.
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",param.Name, left.Name, operation.NodeType, right.Value);
Another great feature of DLR is Call Site caching. It is a dynamic view of method calls or operations of dynamic objects. DLR caches the characteristics of objects and operations and if the operation had been performed earlier than DLR received all necessary information from the cache. Finally, there is a set of classes and interfaces: IDynamicMetaObjectProvider, DynamicMetaObject, DynamicObject and ExpandoObject implemented in DLR.
class MyClass{}
// This code will compile and we get errors in runtime
static void Main(string[] args){
dynamic t = new MyClass();
string str = t.Hello(); // Runtime error
dynamic d = 7.0;
int i = d; // Runtime error 2
}
DLR also gives new opportunities for COM Interop. Now COM objects can be declared as dynamic and there is no reason to bring them to certain types of calls to methods or properties.
excel.Cells[1, 1].Value = "Hello";
// instead
((Excel.Range)excel.Cells[1, 1]).Value2 = "Hello";
Caller information
Who's Your Daddy.
Much emphasis has been placed on the new async capabilities in C# 5.0. However there are smaller -- but still useful -- features of which you may not be aware. There are a few other neat little things Microsoft has added to C# that will help make your code cleaner and easier to maintain. In C# 5.0 you can get information about the caller to a method. You can get file path of the source code, the line number in the source code and the member name of the caller. This information is helpful for tracing, debugging and creating diagnostic tools. Caller Info values are emitted as literals into the Intermediate Language (IL) at compile time.
public void TraceMessage(string message, [CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0) {
Trace.WriteLine("member name: " + memberName);
Trace.WriteLine("source file path: " + sourceFilePath);
Trace.WriteLine("source line number: " + sourceLineNumber);
}
// And
public void OnPropertyChanged([CallerMemberName] string propertyName=null) {
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
In this version we also faced some breaking changes. The first involved foreach loops and lambda expressions. In previous versions of the C# compiler any lambda expression that used the iteration variable within the expression (a "nested lambda expression") captured the last value of the iteration variable, not each value through the loop. Now lambda captures the value instead of reference. The second breaking change is similar to the first one but involves LINQ expressions. Syntactic sugar
The best example of useful sugar is semicolon.
C# 6.0 gives us a lot of syntactic sugar to reduce the amount of code. Some of them look like features of scripting language:
- New keyword nameof gives you a name of property, method or field.
- String interpolation: var s = "\{p.Name} is \{p.Age} year{s} old";
- Expression-bodied function members allow methods, properties and other kinds of function members to have bodies that are expressions instead of statement blocks just like with lambda expressions: public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
Future
Everything new is well forgotten old.
C # continues to evolve and the seventh version can bring a lot of useful and interesting changes. There is a suggestion to add tuples types:
public (int sum, int count) Tally(IEnumerable<int> values) { ... }
var t = Tally(myValues);
Console.WriteLine($"Sum: {t.sum}, count: {t.count}");
// Or
(var sum, var count) = Tally(myValues); // deconstruct result
Console.WriteLine($"Sum: {sum}, count: {count}");
As we can see the code in C # becomes more similar to script and less tied to the types of data. At the same time it affects the performance of the application. So now the development of language is directed towards performance and cloud computing. For these purposes the difference between strongly typed and scripting language should be substantially reduced. And I hope that soon we will be able to use both these languages together (with the same high performance).