7


2

LineDragmasをCodeDomオブジェクトに追加したいという状況があります。 しかし、いくつかのコードDOMオブジェクトはLinePragmaプロパティを持ち、他のものは持っていません。

そのため、動的キーワードを使用して(例外をスローせずに)プロパティがオブジェクト上に存在するかどうかを検出し、プラグマを追加することが可能かどうかを考えています。 これが私の現在の方法です。

public static T SetSource(このT codeObject、INode sourceNode) dynamic dynamicCodeObject = codeObject;

//どうすればここで例外をスローできません if(dynamicCodeObject.LinePragma!= null){dynamicCodeObject.LinePragma = new CodeLinePragma(sourceNode.Source.Path.Abs​​oluteUri、sourceNode.Source.StartLine); }

codeObjectを返します。 }

*更新:*私が行った解決策はExists()と呼ばれる拡張メソッドを追加することでした。 私はそれについてのブログ記事をここに書いた: メンバーが存在する動的C#4.0

その目的は、DynamicObjectのTryGetMemberを実装するオブジェクトを返す拡張メソッドを作成することでした。 リフレクションを使用してtrueまたはfalseを返します。 これにより、次のようなコードを書くことができます。

オブジェクトインスタンス= new {Foo = "Hello World!" ; if(instance.Reflection()。Exists()。Foo){文字列値= instance.Reflection()。Call()。Foo; Console.WriteLine(value); }

6 Answer


8


C#4.0の動的機能を使用せずに、オブジェクトにプロパティがあるかどうかを検出できます - 代わりにしばらく使用されていたリフレクション機能を使用します(少なくとも.NET 2.0を知っています。

PropertyInfo info = codeObject.getType()。GetProperty( "LinePragma"、BindingFlags.Public | BindingFlags.Instance)

そのオブジェクトがプロパティを持たない場合、GetProperty()はnullを返します。 フィールド(GetField())とメソッド(GetMethod())についても同様のことができます。

それだけでなく、一度PropertyInfoを取得したら、それを直接使用して設定を行うことができます。

info.SetValue(codeObject、new CodeLinePragma()、null);

プロパティにsetメソッドがあるかどうかわからない場合は、さらに安全な方法を使用してください。

MethodInfo method = info.GetSetMethod(); if(method!= null)method.Invoke(codeObject、new object [] {new CodeLinePragma()});

これはまた、動的呼び出しのルックアップオーバーヘッドに対してもう少し高性能であるという追加の利点も提供します(そのステートメントの参照を見つけることができないので、ここでは説明しません)。

私はそれがあなたの質問に直接答えるのではなく、むしろ同じ目標を達成するための別の解決策であると思います。 私は実際にはまだ#4.0機能を使っていません(私はRubyで利用可能な動的型付けが大好きですが)。 それは確かに動的な解決策ほどきれいではない/読みやすくはありませんが、あなたが例外を投げたくないならそれが行くべき道かもしれません。

編集:@ arbiterが指摘するように、「これはネイティブの.net動的オブジェクトにのみ有効です。 これはIDispatchなどでは機能しません。」


5


私はちょうど1時間かけて動的にルビー風の "RespondTo"メソッドを得る方法を探していました。 簡単な答えは確かにありませんが、私はまだあきらめていません。

熟考のポイントは試すことです。

動的で、私がこれまでに得た唯一のものはあなたのオブジェクトを動的として扱う拡張メソッドです。 うまくいけばうまくいく、そうでなければ静かに失敗する…

public static void Dynamight(このTターゲット、Actionアクション){dynamic d = target; {action(d);を試してください。 } catch(RuntimeBinderException){//つまり、うまくいかなかった}}

それならあなたは…

文字列h = "こんにちは"。 h.Dynamight(d => Console.WriteLine(d.Length)); // 5 h.Dynamight(d => d.Foo());を印刷する//何も起こりません

更新:

私は賛成票を寄せているので、拡張メソッドの微妙な名前付けよりももっと簡潔にしておきましょう。 例外を飲み込んで何もしないことは*悪い*です。 これは製品コードではありませんが、概念実証の急増のバージョン1です。 私はあなたがstackoverflowのような何千ものフォーラムで微妙になることができないことを忘れ続けています。 ミアカルパ。


3


18か月後…​ それがリリースされた今、あなたが本当に欲しいものがそこにあるようです。 それは* TryGetMember TryGetValue などです。 実際には、おそらく http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.trysetmember.aspx [TrySetMember] *になります。


-1


私は、この問題を避けるために静的型付けを使用することをお勧めします。

これはオーバーライドを伴う抽象メソッドの候補です。


-1


考えてみてください。ターゲットクラスは、(IDynamicObjectの実装またはDynamicObjectのサブクラス化によって)存在しないメンバーのメンバールックアップおよび呼び出しに対して独自の実装を提供できるため、メンバーが存在するかどうかを確認する唯一の方法です。 objectはそれを処理するか、または例外を投げます*。

繰り返しますが、存在しないメンバーの処理は動的です。

  • 編集 -

オブジェクトの作成を制御する場合は、そのクラスをサブクラス化してIDynamicObjectを実装し、他のクラスにそのメソッドが存在しないことを通知することができます。

それが真実を指摘している場合、答えを軽視するのは不公平です。 *動的ディスパッチ環境でメンバーの存在を確認するための信頼できる方法ではありません。メンバーを呼び出す以外にはできません。


-1


System.Collections.Genericを使用します。 System.Linq.Expressionsを使用します。

namespace System.Dynamic {// //概要://実行時に動的動作を指定するための基本クラスを提供します。 このクラスは//から継承する必要があります。直接インスタンス化することはできません。 public class DynamicObject:IDynamicMetaObjectProvider {// //概要://派生型がSystem.Dynamic.DynamicObject型の新しいインスタンスを初期化できるようにします。 protected DynamicObject();

// //要約://すべての動的メンバー名の列挙を返します。 // //戻り値://動的メンバー名を含むシーケンス。 パブリック仮想IEnumerable GetDynamicMemberNames(); // //概要://動的仮想メソッドにディスパッチするSystem.Dynamic.DynamicMetaObjectを提供します。 オブジェクトを別のSystem.Dynamic.DynamicMetaObject //の中にカプセル化して、個々のアクションにカスタム動作を提供することができます。 このメソッドは、言語実装者向けのDynamic // Language Runtimeインフラストラクチャをサポートします。これは、コードから直接使用するためのものではありません。 // //パラメータ:// parameter://動的仮想メソッドにディスパッチするSystem.Dynamic.DynamicMetaObjectを表す式。 // //戻り値:// System.Dynamic.DynamicMetaObject型のオブジェクト。 パブリック仮想DynamicMetaObject GetMetaObject(式パラメータ)。 // //概要://二項演算の実装を提供します。 System.Dynamic.DynamicObjectクラスから派生したクラスは、このメソッドをオーバーライドして、加算や乗算などの操作に対する動的な動作を指定できます。 // //パラメータ:// binding://二項演算に関する情報を提供します。 binding.OperationプロパティはSystem.Linq.Expressions.ExpressionTypeオブジェクトを返します。 たとえば、// sum = first secondステートメントで、firstとsecondが// DynamicObjectクラスから派生している//場合、binding.OperationはExpressionType.Addを返します。 // // arg://二項演算の右オペランド。 たとえば、sum = first // secondステートメントで、firstとsecondがDynamicObject //クラスから派生している場合、argはsecondに等しくなります。 // // result://二項演算の結果。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合//言語固有の実行時例外がスローされます。)public virtual bool TryBinaryOperation(BinaryOperationBinderバインダー、object arg、outオブジェクト結果)。 // //概要://型変換操作の実装を提供します。 System.Dynamic.DynamicObjectクラスから派生したクラスは、このメソッドをオーバーライドして、オブジェクトをある型から別の型に変換する操作の動的な動作を指定できます。 // //パラメータ:// binding://変換操作に関する情報を提供します。 binding.Typeプロパティは、オブジェクトの変換先の型を提供します。 たとえば、C#の// statement(String)sampleObject(Visual BasicではCType(sampleObject、Type))の場合、// sampleObjectはSystem.Dynamic.DynamicObjectクラスのバインダから派生したクラスのインスタンスです。 TypeはSystem.String型を返します。 binding.Explicitプロパティ//は、発生した変換の種類に関する情報を提供します。 明示的な変換の場合はtrue //、暗黙の変換の場合はfalseを返します。 // // result://型変換操作の結果。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合//言語固有の実行時例外がスローされます。)public virtual bool TryConvert(ConvertBinderバインダー、outオブジェクトの結果)。 // //概要://動的オブジェクトの新しいインスタンスを初期化する操作の実装を//提供します。 このメソッドは、C#またはVisual Basicでの使用を目的としていません。 // //パラメータ:// binding://初期化操作に関する情報を提供します。 // // args://初期化中にオブジェクトに渡される引数。 たとえば、// SampleTypeがSystem.Dynamic.DynamicObjectクラスから派生した型である//新しいSampleType(100)操作の場合、args [0]は100になります。 // // result://初期化の結果 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合//言語固有の実行時例外がスローされます。)public virtual bool TryCreateInstance(CreateInstanceBinderバインダー、object [] args、outオブジェクトの結果)。 // //要約://インデックスでオブジェクトを削除する操作の実装を提供します。 このメソッドはC#またはVisual Basicでの使用を意図していません。 // //パラメータ:// binding://削除に関する情報を提供します。 // // indexes://削除するインデックス。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合、//言語固有の実行時例外がスローされます。) // //概要://オブジェクトメンバを削除する操作の実装を提供します。 このメソッドはC#またはVisual Basicでの使用を意図していません。 // //パラメータ:// binding://削除に関する情報を提供します。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合、//言語固有の実行時例外がスローされます。) // //概要://インデックスで値を取得する操作の実装を提供します。 // System.Dynamic.DynamicObjectクラスから派生したクラスは、このメソッドをオーバーライドして、インデックス付け操作の動的動作を指定できます // //パラメータ:// binding://操作に関する情報を提供します。 // // indexes://操作に使用されるインデックス。 たとえば、sampleObjectがDynamicObjectクラスから派生している// C#のsampleObject [3] //操作(Visual BasicではsampleObject(3))の場合、indexes [0]は3です。 // // result://インデックス操作の結果。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合、実行時例外がスローされます。) // //概要://メンバ値を取得する操作の実装を提供します。 System.Dynamic.DynamicObjectクラスから派生したクラスは、このメソッドをオーバーライドして、プロパティの値の取得などの操作に対する動的な動作を指定できます。 // //パラメータ:// binding://動的操作を呼び出したオブジェクトに関する情報を提供します。 // binding.Nameプロパティは、動的操作が実行されるメンバーの名前を提供します。 たとえば、console.WriteLine(sampleObject.SampleProperty)//ステートメント(sampleObjectはSystem.Dynamic.DynamicObjectクラスから派生したクラスのインスタンスです)//ステートメントの場合、binding.Nameは "SampleProperty"を返します。 binding.IgnoreCaseプロパティは、//メンバー名が大文字と小文字を区別するかどうかを//指定します。 // // result:// get操作の結果。 たとえば、メソッドがプロパティに対して呼び出された場合、//プロパティ値をresultに割り当てることができます。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合//ランタイム例外がスローされます。)public virtual bool TryGetMember(GetMemberBinderバインダー、outオブジェクトの結果)。 // //概要://オブジェクトを呼び出す操作の実装を提供します。 System.Dynamic.DynamicObjectクラスから派生したクラスは、このメソッドをオーバーライドして、オブジェクトやデリゲートの呼び出しなどの操作に対する動的な動作を指定できます。 // //パラメータ:// binding://呼び出し操作に関する情報を提供します。 // // args://呼び出し操作中にオブジェクトに渡される引数。 //たとえば、sampleObjectがSystem.Dynamic.DynamicObjectクラスから派生している// sampleObject(100)操作の場合、args [0]は100になります。 // // result://オブジェクト呼び出しの結果 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合、//言語固有の実行時例外がスローされます。 公開仮想ブールTryInvoke(InvokeBinderバインダー、object []引数、outオブジェクト結果) // //概要://メンバーを呼び出す操作の実装を提供します。 System.Dynamic.DynamicObjectクラスから派生したクラスは、このメソッドをオーバーライドして、メソッドの呼び出しなどの操作に対する動的な動作を指定できます。 // //パラメータ:// binding://動的操作に関する情報を提供します。 binding.Nameプロパティは、動的操作が実行されるメンバの名前を//提供します。 たとえば、// sampleObject.SampleMethod(100)というステートメントの場合、sampleObjectは、System.Dynamic.DynamicObjectクラスから派生したクラスのインスタンス// //で、binding.Nameは "SampleMethod"を返します。 binding.IgnoreCaseプロパティは、//メンバ名の大文字と小文字を区別するかどうかを指定します。 // // args://呼び出し操作中にオブジェクトメンバーに渡される引数。 //たとえば、sampleObjectがSystem.Dynamic.DynamicObjectクラスから派生した// sampleObject.SampleMethod(100)の場合、args [0]は100になります。 // // result://メンバー呼び出しの結果。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合//言語固有の実行時例外がスローされます。) // //概要://インデックスで値を設定する操作の実装を提供します。 // System.Dynamic.DynamicObjectクラスから派生したクラスは、このメソッドをオーバーライドして、指定されたインデックスによってオブジェクトにアクセスする操作の動的な動作を指定できます。 // //パラメータ:// binding://操作に関する情報を提供します。 // // indexes://操作に使用されるインデックス。 たとえば、C#のsampleObject [3] // = 10操作(Visual BasicではsampleObject(3)= 10)の場合、sampleObject //はSystem.Dynamic.DynamicObjectクラスから派生したもので、indexes [0]は次のようになります。 // 3。 // // value://指定されたインデックスを持つオブジェクトに設定する値。 例えば、// C#のsampleObject [3] = 10操作(Visual BasicではsampleObject(3)= 10)の場合、// sampleObjectはSystem.Dynamic.DynamicObjectクラスから派生した//値で、//は10です。 。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合、//言語固有の実行時例外がスローされます。 パブリック仮想ブールTrySetIndex(SetIndexBinderバインダー、object []インデックス、オブジェクト値); // //概要://メンバ値を設定する操作の実装を提供します。 System.Dynamic.DynamicObjectクラスから派生したクラスは、このメソッドをオーバーライドして、プロパティの値の設定などの操作に対する動的な動作を指定できます。 // //パラメータ:// binding://動的操作を呼び出したオブジェクトに関する情報を提供します。 // binding.Nameプロパティは、値が割り当てられているメンバーの名前を提供します。 たとえば、sampleObject.SampleProperty = "Test"、//の場合、sampleObjectはSystem.Dynamic.DynamicObjectクラスから派生したクラスのインスタンスであり、//バインダーの名前はSamplePropertyを返します。 binding.IgnoreCaseプロパティは、//メンバー名が大文字と小文字を区別するかどうかを//指定します。 // // value://メンバーに設定する値。 たとえば、sampleObject.SampleProperty // = "Test"の場合、sampleObjectはSystem.Dynamic.DynamicObject //クラスから派生したクラスのインスタンスであり、値は "Test"です。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合、//言語固有の実行時例外がスローされます。) // //要約://単項演算の実装を提供します。 // System.Dynamic.DynamicObjectクラスから派生したクラスは、このメソッドをオーバーライドして、否定、増加、減少などの操作に対する動的な動作を指定できます。 // //パラメータ:// binding://単項演算に関する情報を提供します。 binding.OperationプロパティはSystem.Linq.Expressions.ExpressionTypeオブジェクトを返します。 たとえば、// negativeNumber = -numberステートメントの場合、numberはDynamicObjectクラスから派生している// //場合、binding.Operationは "Negate"を返します。 // // result://単項演算の結果。 // //戻り値://操作が成功した場合はtrue。そうでなければ、偽です。 このメソッドが// falseを返す場合、言語の実行時バインダーが動作を決定します。 (ほとんどの場合//言語固有の実行時例外がスローされます。)ここにコードを入力してください。