DynamicObject
is just such a feature that seems simple and understandable, but in playful pens it becomes a more dangerous undertaking.System.Dynamic.DynamicObject
class is. This class seems to be ordinary - from it, for example, one can follow and overload one or more of its methods. Only here are some difficult methods ... let's take a closer look.DO
test object and inherit from DynamicObject
:class DO : DynamicObject {}
dynamic
keyword, we can invoke any method on this object without any remorse of conscience:dynamic dobj = new DO();
dobj.NonExistentMethod();
RuntimeBinderException
something called RuntimeBinderException
and here’s the message.'DynamicObjectAbuse.DO' does not contain a definition for 'NonExistentMethod'
NonExistentMethod()
method in our class simply does not exist. And the interesting thing is that it may never be. That's the whole DynamicObject
- the ability to call properties and methods that the class doesn't have . Either not at the time of compilation, or not at all.bool TryInvokeMember(InvokeMemberBinder binder, object [] args, out object result)
NonExistentMethod()
method, this method is called without arguments, and the binder
parameter just contains information about the call.{Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder}
[Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder]: {Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder}
base {System.Dynamic.DynamicMetaObjectBinder}: {Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder}
CallInfo: {System.Dynamic.CallInfo}
IgnoreCase: false
Name: "NonExistentMethod"
ReturnType: {Name = "Object" FullName = "System.Object" }
args
) and returning a result ( result
). The method returns true
if everything was successful or false
if everything was covered. Returning false
from this method just causes an exception that we saw above.DynamicObject
impressive. This is primarily the ability to respond to access to properties that do not exist, as well as to conversions, unary and binary operators, access via an index, etc. Some operations are generally not intended for C # / VB — for example, intercepting object creation, deleting object members, deleting an object by index, etc.this
you will receive a static DO
object instead of a statically typed dynamic DO
. The solution to this problem is predictable:private dynamic This { get { return this ; } }
This
from TryInvokeMember()
because you simply get StackOverflowException
.ExpandoObject
is generally a swan song. This class allows users to arbitrarily add methods and properties:dynamic eo = new ExpandoObject();
eo.Name = "Dmitri" ;
eo.Age = 25;
eo.Print = new Action(() =>
Console.WriteLine( "{0} is {1} years old" ,
eo.Name, eo.Age));
eo.Print();
IDictionary
- an interface that is not serialized, for example, in XML due to some very muddy reasons related to the fragmentation of assemblies and interfaces. No matter. If you really need to, you can use the System.Runtime.Serialization.DataContractSerializer
:var s = new DataContractSerializer( typeof (IDictionary< string , object >));
var sb = new StringBuilder();
using ( var xw = XmlWriter.Create(sb))
{
s.WriteObject(xw, eo);
}
Console.WriteLine(sb.ToString());
DataContractResolver
, but the purpose of this article is not to use such practices.XElement
looks simply inhuman:var xe = XElement.Parse(something);
var name = xe.Elements( "People" ).Element( "Dmitri" ).Attributes( "Name" ).Value; // WTF?
DynamicObject
, which with its virtual properties resolves the contents of XElement
:public class DynamicXMLNode : DynamicObject
{
XElement node;
public DynamicXMLNode(XElement node)
{
this .node = node;
}
public DynamicXMLNode()
{
}
public DynamicXMLNode(String name)
{
node = new XElement(name);
}
public override bool TrySetMember(
SetMemberBinder binder, object value )
{
XElement setNode = node.Element(binder.Name);
if (setNode != null )
setNode.SetValue( value );
else
{
if ( value .GetType() == typeof (DynamicXMLNode))
node.Add( new XElement(binder.Name));
else
node.Add( new XElement(binder.Name, value ));
}
return true ;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
XElement getNode = node.Element(binder.Name);
if (getNode != null )
{
result = new DynamicXMLNode(getNode);
return true ;
}
else
{
result = null ;
return false ;
}
}
}
var xe = XElement.Parse(something);
var dxn = new DynamicXmlNode(xe);
var name = dxn.people.dmitri.name;
NullReferenceException
thrown, even if one of the elements in the chain is really null
. To do this, you really have to make fake objects, but this is akin to creating intermediate classes for fluent interfaces.DynamicXmlNode
is DSL for which XML is a domain. In the same way, I can for example write the following:myobject.InvokeEachMethodThatBeginsWithTest()
DynamicObject
we will stupidly InvokeEachMethod...
line InvokeEachMethod...
and then react to it accordingly. In this case, we will use reflection. Of course, this means that any use of this functionality as a DSL is a) completely undocumented and incomprehensible to an outsider; and b) is limited to identifier naming rules. It will not be possible for example to compile the following:DateTime dt = (DateTime)timeDO.friday.13.fullmoon;
friday13
will work. However, there are already (and probably used in production) extension methods like July()
that allow you to write very cryptic code like 4.July(2010)
. As for me, this is not cool at all.DynamicObject
mechanism for their infernal purposes:Source: https://habr.com/ru/post/96988/
All Articles