📜 ⬆️ ⬇️

Interesting things you can do with dynamic in .NET 4.0

In the " C # 4.0 Review " article, I discussed some of the new features of the fourth version of the C # language. It so happened that I did not consider one of the most important innovations: the dynamic keyword.

Simply put, an object of type dynamic does not have strict semantics of use at the compilation stage. All instance members are determined at runtime using the Dynamic Language Runtime (DLR). Here is a simple example:
static void Main( string [] args)
{
dynamic int1 = 1;
dynamic int2 = 2;
dynamic result = int1 + int2;
Console .WriteLine(result);
}

* This source code was highlighted with Source Code Highlighter .

As expected, this code will print "3." However, the “+” operator and what, in fact, are the variables int1 and int2 will definitely not at compile time, but at run time. I will show you another example (it looks like it should not compile, but, in fact, this is all right with it):
static void Main( string [] args)
{
dynamic int1 = 1;
dynamic ex1 = new Exception( "Oops!" );
dynamic result = int1 + ex1;
Console .WriteLine(result);
}

* This source code was highlighted with Source Code Highlighter .

In fact, such code should not be compiled, since the “+” operator is not defined for a pair of arguments of type int and Exception. But, since we use dynamic, the code will compile, and already at the execution stage we will get an exception:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Operator '+' cannot be applied to operands of type 'int' and 'System.Exception'

How can you use all this? Why can't we use real types instead of dynamic? A possible scenario for the use of innovation: if at the compilation stage we do not know what type of object or if we obtained an object from an unusual source, for example, using reflection. Previously, when using reflection, it was necessary to use tricks like the Invoke or GetProperty methods, now it is enough to define the object as dynamic and use an intuitively clear syntax. The same situation arises when COM Interop is used: if the object does not implement the full wrapper on .NET, we can use dynamic and safely use it without writing a lot of code for the wrapper mechanism.
But the most interesting use of dynamic is to define your own dynamic types. To do this, .NET 4.0 introduced a new base type - DynamicObject. It allows you to determine how an object should behave at run time, and how it will process its properties and methods. With it, it becomes possible to build some powerful and useful tools.
I worked a bit with PowerShell, and what impressed me was how easy it was to work with XML. Here is a piece of PowerShell code that loads the XML file:
$xmlConfig = New-Object XML
$xmlConfig.Load(”Some XML Path”);
$backup = ($xmlConfig.configuration.appSettings.add | where {$_.key –eq 'BackupEveryInMinutes'}). value ;

* This source code was highlighted with Source Code Highlighter .

The file itself looks like this:
< configuration >
< appSettings >
< add key ="BackupEveryInMinutes" value ="1440" />
</ appSettings >
</ configuration >

* This source code was highlighted with Source Code Highlighter .

Thus, the variable $ backup will be assigned the value "1440". I liked this way of accessing the $ xmlConfig properties as if they were always there. In previous versions of C # and .NET, this was not possible. However, using DynamicObject we can create an object that can work in exactly the same way. Let's start now!
Create a class that inherits from DynamicObject:
public class DynamicXml : DynamicObject
{
}

* This source code was highlighted with Source Code Highlighter .

The most important thing here is to override the TryGetMember method. This is the way we tell the DLR how to dynamically determine a member of a class.
public class DynamicXml : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
}
}

* This source code was highlighted with Source Code Highlighter .

Let's take a closer look at the parameters: “binder” is what we are trying to determine, a parameter that tells us what the DLR is trying to call the object (for example, it could be the name of a property). The “result” parameter is the result of the call to return to the DLR. The method returns “True” if it was possible to successfully determine the member of the dynamic object and “False” if not. In our case, we will return “False” if the XML does not contain the vertex we are trying to access. This, in turn, will cause an exception in the DLR at run time.
The object constructor will accept an XmlNode object as a parameter. In our case, we will load the XmlDocument and pass it, since it is inherited from the XmlNode.
So we can use our class like this:
XmlDocument document = new XmlDocument ();
document.Load(”pathtoxml.xml”);
dynamic dynamicXml = new DynamicXml(document);
string value = dynamicXml.configuration.appSettings.add. value ;


* This source code was highlighted with Source Code Highlighter .

The properties used in dynamicXml are the vertices of the XML that we are trying to access. We can see in the binder parameter what property is being accessed and, if necessary, recursively return our dynamic object for continuation. As a result, we get something like this:
using System.Xml;
using System.Collections. Generic ;
using System.Dynamic;

namespace CSharp4
{
public class DynamicXml : DynamicObject
{
private readonly XmlNode _node;

public DynamicXml( XmlNode node)
{
_node = node;
}

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null ;
XmlNodeList nodes = _node.SelectNodes(binder.Name);
if (nodes.Count == 0)
nodes = _node.SelectNodes( "@" + binder.Name); //Check and see if it's an attribute.
if (nodes.Count == 0)
return false ;
if (nodes.Count == 1)
{
XmlNode node = nodes[0];
result = GetContent(node);
}
else
{
List <dynamic> results = new List <dynamic>();
foreach ( XmlNode node in nodes)
{
results.Add(GetContent(node));
}
result = results;
}
return true ;
}

private dynamic GetContent( XmlNode node)
{
if (node.NodeType == XmlNodeType . Attribute )
return node.Value;
if (node.HasChildNodes || node.Attributes.Count > 0)
return new DynamicXml(node);
return node.InnerText;
}

public override string ToString()
{
return this ;
}

public static implicit operator string (DynamicXml xml)
{
return xml._node.InnerText;
}
}
}

* This source code was highlighted with Source Code Highlighter .

Of course, it is not perfect. It could handle collections in a more correct way than simply returning a list and supporting other types than the string. And this is not the best solution in this case, there are the same XDocument and LINQ, which are the best alternative when working with XML. However, I think this is a great illustration of the power of dynamic that C # 4.0 has brought us.
Progg it

')

Source: https://habr.com/ru/post/79139/


All Articles