2

ディクショナリ内のすべてのエントリが既知のタイプである DynamicDictionary の実装があります。

public class FooClass
{
    public void SomeMethod()
    {
    }
}

dynamic dictionary = new DynamicDictionary<FooClass>();

dictionary.foo = new FooClass();
dictionary.foo2 = new FooClass();
dictionary.foo3 = DateTime.Now;  <--throws exception since DateTime is not FooClass

私が望むのは、辞書エントリの 1 つのメソッドを参照するときに Visual Studio Intellisense を機能させることです。

dictionary.foo.SomeMethod()  <--would like SomeMethod to pop up in intellisense

これを行うために私が見つけた唯一の方法は次のとおりです。

((FooClass)dictionary.foo).SomeMethod()

よりエレガントな構文を推奨できる人はいますか? IDynamicMetaObjectProvider を使用して DynamicDictionary のカスタム実装を作成することに問題はありません。

アップデート:

なぜダイナミクスなのか、そして私の特定の問題は何かと尋ねる人もいます。次のようなことができるシステムがあります。

UI.Map<Foo>().Action<int, object>(x => x.SomeMethodWithParameters).Validate((parameters) =>
{
    //do some method validation on the parameters
    return true;  //return true for now
}).WithMessage("The parameters are not valid");

この場合、メソッド SomeMethodWithParameters には署名があります

public void SomeMethodWithParameters(int index, object target)
{
}

個々のパラメーターの検証を登録するために現在持っているものは次のようになります。

UI.Map<Foo>().Action<int, object>(x => x.SomeMethodWithParameters).GetParameter("index").Validate((val) =>
{
     return true;  //valid
}).WithMessage("index is not valid");

私がしたいのは:

UI.Map<Foo>().Action<int, object(x => x.SomeMethodWithParameters).index.Validate((val) =>
{
    return true;
}).WithMessage("index is not valid");

これはダイナミクスを使用して機能しますが、インデックスへの参照後にインテリセンスが失われます。これは今のところ問題ありません。問題は、Visual Studio に何らかの形で型を認識させるための巧妙な構文上の方法 (上記のもの以外) があるかどうかです。これまでのところ、答えは「いいえ」のようです。

IDynamicMetaObjectProvider の汎用バージョンがあれば、

IDynamicMetaObjectProvider<T>

これは機能する可能性があります。しかし、そうではないので、質問です。

4

3 に答える 3

4

dynamicインテリセンスを取得するには、ある時点ではない値に何かをキャストする必要があります。これを頻繁に行う場合は、ヘルパー メソッドを使用して多少の負担を軽減できます。

GetFoo(dictionary.Foo).SomeMethod();

しかし、それはあなたがすでに持っているものよりも多くの改善ではありません. インテリセンスを取得する他の唯一の方法は、値を非動的な型にキャストするかdynamic、最初から回避することです。

Intellisense を使用する場合は、通常、最初から使用しないことをお勧めしますdynamic

typedDictionary["foo"].SomeMethod();

あなたの例は、dynamicオブジェクトの構造について特定の期待を持っている可能性が高いように思われます。ニーズを満たす静的クラス構造を作成する方法があるかどうかを検討してください。

アップデート

あなたの更新に応じて:構文を大幅に変更したくない場合は、構文が次のようになるようにインデクサーを使用することをお勧めします。

UI.Map<Foo>().Action<int, object>(x => x.SomeMethodWithParameters)["index"].Validate((val) => {...});

これが私の推論です:

  1. 動的なアプローチと比較して、追加するのは 4 文字 (および 1 を減算する) だけです。
  2. それに直面しましょう:あなたは「魔法の糸」を使っています。実際の文字列を要求することで、この事実は、このコードを見たプログラマーにとってすぐに明らかになります。このdynamicアプローチを使用すると、「インデックス」がコンパイラの観点から既知の値ではないことを示すものは何もありません。

物事をかなり変更したい場合はMoq、構文、特にIt.IsAny<T>()メソッドで式を操作する方法を調査することをお勧めします。次の行に沿って、さらに何かできるようです。

UI.Map<Foo>().Action(
    (x, v) => x.SomeMethodWithParameters(
        v.Validate<int>(index => {return index > 1;})
            .WithMessage("index is not valid"),
        v.AlwaysValid<object>()));

現在のソリューションとは異なります。

  1. メソッド シグネチャ内のパラメーターの名前を変更しても、これは壊れません。コンパイラと同様に、フレームワークは、パラメーターの名前よりもパラメーターの場所と型に注意を払います。
  2. メソッド シグネチャを変更すると、コードの実行時に実行時例外ではなく、コンパイラからの即時フラグが発生します。

(式ツリーの解析を必要としないため) おそらく達成するのが少し簡単な別の構文は次のようになります。

UI.Map<Foo>().Action((x, v) => x.SomeMethodWithParameters)
    .Validate(v => new{
        index = v.ByMethod<int>(i => {return i > 1;}),
        target = v.IsNotNull()});

これにより、上記の利点が得られるわけではありませんが、型の安全性 (したがってインテリセンス) は得られます。あなたの毒を選んでください。

于 2012-04-21T04:51:18.970 に答える
2

明示的なキャストは別として、

((FooClass)dictionary.foo).SomeMethod();

またはセーフキャスト

(dictionary.foo as FooClass).SomeMethod();

静的呼び出しに戻す唯一の他の方法 (これにより、インテリセンスが機能するようになります) は、Implicit Castを実行することです。

FooClass foo = dictionary.foo;
foo.SomeMethod().

宣言されたキャストが唯一のオプションです。ヘルパー メソッドは動的に呼び出されて同じ問題が発生するため、使用できません。

アップデート:

これがよりエレガントかどうかはわかりませんが、束をキャストする必要はなく、ラムダの外でインテリセンスを取得します:

public class DynamicDictionary<T>:IDynamicMetaObjectProvider{

    ...

    public T Get(Func<dynamic,dynamic> arg){
            return arg(this);
    }

    public void Set(Action<dynamic> arg){
            arg(this);
    }
}
...
var dictionary = new DynamicDictionary<FooClass>();

dictionary.Set(d=>d.Foo = new FooClass());
dictionary.Get(d=>d.Foo).SomeMethod(); 
于 2012-04-24T17:55:24.407 に答える
0

すでに述べたように (質問とStriplingWarriorの回答で)、C# 4dynamicタイプはインテリセンス サポートを提供しません。この回答は、理由を説明するためだけに提供されています(私の理解に基づいています)。

dynamicC# コンパイラにとって、objectどのメンバーがサポートするかは、コンパイル時に限られた知識しか持っていないだけです。違いは、実行時に、dynamicそのインスタンスに対して呼び出されたメンバーを、それが表すインスタンスが認識している型に対して解決しようとすることです (遅延バインディングの形式を提供します)。

次の点を考慮してください。

dynamic v = 0;
v += 1;
Console.WriteLine("First: {0}", v);
// ---
v = "Hello";
v += " World";
Console.WriteLine("Second: {0}", v);

このスニペットでは、 は(コードの最初のセクションで見られるように) のインスタンスと後者のvのインスタンスの両方を表します。関連する型は実行時に推論されるため、演算子の使用は実際には 2 つの異なる呼び出し間で異なります (つまり、コンパイラはコンパイル時に型の使用法を理解または推論しません)。Int32String+=

ここで、わずかなバリエーションを考えてみましょう:

dynamic v;

if (DateTime.Now.Second % 2 == 0)
    v = 0;
else
    v = "Hello";

v += 1;
Console.WriteLine("{0}", v);

この例では、コードが実行される時間に応じて、 がまたはvなる可能性があります。極端な例ですが、問題を明確に示しています。Int32 String

単一のdynamic変数が実行時に任意の数の型を表す可能性があることを考慮すると、コンパイラまたは IDE が実行前にそれが表す型について推測することはほぼ不可能です。そのため、dynamic変数の設計時またはコンパイル時の解決潜在的なメンバーは不合理です(不可能ではないにしても)。

于 2012-04-21T05:16:02.047 に答える