.NET 4.0でのダイナミックに関する興味深いこと

C#4.0 Reviewの記事で、C#の4番目のバージョンの新機能について説明しました。 そのため、私は最も重要なイノベーションの1つである動的キーワードを検討しませんでした。



簡単に言えば、タイプがdynamicのオブジェクトには、コンパイル時の厳密な使用セマンティクスがありません。 すべてのインスタンスメンバーは、実行時にDynamic Language Runtime(DLR)を使用して決定されます。 以下に簡単な例を示します。

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 .






ご想像のとおり、このコードは「3」を出力します。 ただし、実際には、「+」演算子とint1およびint2変数は、コンパイル段階ではなく、実行時に確実に存在します。 別の例を示します(コンパイルすべきではないように見えますが、実際にはすべて問題ありません)。

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 .






実際、int型とException型の引数のペアに対して「+」演算子が定義されていないため、このようなコードをコンパイルする必要はありません。 ただし、動的を使用するため、コードがコンパイルされ、実行時に既に例外が発生します。

未処理の例外:Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:演算子 '+'は、タイプ 'int'および 'System.Exception'のオペランドに適用できません


これらすべてをどのように使用できますか? 動的ではなく実際の型を使用できないのはなぜですか? イノベーションを使用するための可能なシナリオ:コンパイル段階でオブジェクトのタイプがわからない場合、またはリフレクションを使用するなど、異常なソースからオブジェクトを受信した場合。 以前は、リフレクションを使用する場合、InvokeやGetPropertyメソッドなどのトリックを使用する必要がありましたが、今ではオブジェクトを動的として定義し、直感的な構文を使用するだけで十分です。 COM Interopを使用する場合も同じ状況が発生します。オブジェクトに完全な.NETラッパーがない場合は、ラッパーメカニズム用の多くのコードを記述せずに動的に使用し、静かに使用できます。

しかし、ダイナミックの最も興味深い使用法は、独自のダイナミックタイプを定義することです。 これを行うために、.NET 4.0は新しい基本型DynamicObjectを導入しました。 これにより、実行時にオブジェクトがどのように動作するか、およびプロパティとメソッドをどのように処理するかを決定できます。 これにより、いくつかの強力で便利なツールを構築することが可能になります。

PowerShellを少し使用しましたが、私が驚いたのは、XMLを簡単に操作できることです。 XMLファイルを読み込むPowerShellコードの一部を次に示します。

$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 .






ファイル自体は次のようになります。

< configuration >

< appSettings >

< add key ="BackupEveryInMinutes" value ="1440" />

</ appSettings >

</ configuration >



* This source code was highlighted with Source Code Highlighter .






したがって、$バックアップ変数には値「1440」が割り当てられます。 $ xmlConfigプロパティに常にアクセスするかのようにアクセスするこの方法が気に入りました。 C#および.NETの以前のバージョンでは、これは不可能でした。 ただし、DynamicObjectを使用すると、まったく同じように機能するオブジェクトを作成できます。 始めましょう!

DynamicObjectから継承するクラスを作成します。

public class DynamicXml : DynamicObject

{

}


* This source code was highlighted with Source Code Highlighter .






ここで最も重要なことは、TryGetMemberメソッドをオーバーライドすることです。 これは、クラスのメンバーを動的に決定する方法をDLRに伝える方法です。

public class DynamicXml : DynamicObject

{

public override bool TryGetMember(GetMemberBinder binder, out object result)

{

}

}


* This source code was highlighted with Source Code Highlighter .






パラメーターを詳しく見てみましょう。「バインダー」は、私たちが決定しようとしているもの、DLRがオブジェクトを呼び出しようとしていることを正確に伝えるパラメーターです(たとえば、プロパティの名前かもしれません)。 「結果」パラメーターは、DLRによって返される呼び出しの結果です。 このメソッドは、動的オブジェクトのメンバーを正常に判別できた場合は「True」を返し、そうでない場合は「False」を返します。 この例では、アクセスしようとしている頂点がXMLに含まれていない場合、「False」を返します。 これにより、DLRでランタイム例外がスローされます。

オブジェクトのコンストラクターは、パラメーターとしてXmlNode型のオブジェクトを受け入れます。 この場合、XmlNodeを継承するため、XmlDocumentをロードして渡します。

したがって、次のようにクラスを使用できます。

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 .






dynamicXmlで使用されるプロパティは、アクセスしようとしているXMLの頂点です。 プロパティにアクセスするバインダーパラメータを調べ、必要に応じて、動的オブジェクトを再帰的に返して続行します。 その結果、次のコードのようなものが得られます。

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 .






もちろん、彼は完璧ではありません。 リストを返すだけでなく、文字列以外の型をサポートするよりも適切な方法でコレクションを処理できます。 そして、これはこの場合の最善の解決策とはほど遠いです。同じXDocumentとLINQがあり、これらはXMLを操作する際の最適な代替手段です。 しかし、これはC#4.0がもたらしたダイナミックな力の素晴らしい例だと思います。

プログイット




All Articles