web-dev-qa-db-ja.com

匿名型をメソッドパラメータとして渡す

私のプラグインアーキテクチャでは、プラグイン名(文字列)、メソッド名(文字列)、パラメーター(オブジェクト配列)をプラグインサービスに渡して、指定されたメソッドを実行し、結果(T型)を返します。

プラグインサービスの実行メソッドを以下に示します。

public TResult Execute<TResult>(string pluginName, string operation, params object[] input) {
    MethodInfo method = null;
    TResult result = default(TResult);

    var plugin = _plugins.Enabled().FirstOrDefault(x => x.GetType().Name.Equals(pluginName,  StringComparison.InvariantCultureIgnoreCase));

    if (plugin != null) {
        method = plugin.GetType().GetMethods().FirstOrDefault(x => x.Name == operation);
        if (method != null) {
            result = (TResult)method.Invoke(plugin, input);
        }
    }
    return result;
  }

使用例:

var url = AppHelper.PluginService.Execute<string>(
    "ImagePlugin",
    "GetImageUrl",
    new object[] { image, size });

私がむしろやりたいのは、代わりに匿名型で渡すことです(これはより読みやすいと思います)。

var url = AppHelper.PluginService.Execute<string>(
    "ImagePlugin",
    "GetImageUrl",
    new { image = image, targetSize = size });

匿名メソッドのプロパティをプラグインメソッドのパラメーターにマップするようにExecuteメソッドをどのように変更しますか?

私は.net 4.0で新しい動的タイプを使用することを検討しましたが、1つの動的オブジェクトを受け入れるのではなく、プラグインメソッドでパラメーターを定義することを好みます。

ありがとうベン

[更新]

ASP.NET MVCソースコードを調べたところ、匿名タイプをオブジェクトディクショナリ(たとえば、 RouteValueDictionary。リフレクションを利用して、linq式が動的に作成されます。これは適切な実装ですが、このような複雑さのすべてを本当に望んでいませんでした。

以下のコメントのとおり、パラメーターをインラインで指定するだけで読みやすさを実現できます(オブジェクト配列宣言は必要ありません)。

var url = AppHelper.PluginService.Execute<string>("ImagePlugin", "GetImageUrl", image, size);
22
Ben Foster

これを可能にする方法はいくつかありますが、アドバイスはしません。

まず、リフレクションを使用できます。つまり、必要な値を取得するには、PluginService.Executeメソッドに多くの追加の(エラーが発生しやすい)コードを記述する必要があります。

次に、メソッドに渡す匿名型のパラメーターがわかっている場合は、説明されている手法 here を使用できます。メソッド内で、同じプロパティを持つ別の匿名型にキャストできます。 ここ は、ジョンスキートによる同じ手法の別の説明です。

3番目に、 System.ComponentModel のクラスを使用できます。たとえば、ASP.NET MVCはこれを使用します。フードの下での反射を使用します。ただし、ASP.NET MVCでは、プロパティ名はよく知られている(たとえば、controllerおよびaction)か、そのままの形でコントローラーメソッドに渡されるため、それらの名前は重要ではありません。 (たとえば、id)。

9

私は最終的には遭遇しました この投稿 これは、匿名型を辞書として使用する方法を示しています。このメソッドを使用すると、匿名型をメソッドパラメータ(オブジェクト)として渡し、そのプロパティにアクセスできます。

ただし、ExpandoObjectなどの.net 4.0の新しい動的機能を調べた後、動的オブジェクトをパラメーターとして渡す方がはるかにわかりやすいことも追加します。

        dynamic myobj = new ExpandoObject();
        myobj.FirstName = "John";
        myobj.LastName = "Smith";

        SayHello(myobj);
        ...........

        public static void SayHello(dynamic properties)
        {
           Console.WriteLine(properties.FirstName + " " + properties.LastName);
        }
21
Ben Foster

匿名型を渡す場合は、パラメーターに動的オブジェクトを使用します。プラグインの実行メソッドは、機能するためにパラメーターオブジェクトの特定のプロパティを予期する必要があります。動的キーワードを使用することにより、C#コンパイラはパラメーターの型チェックを実行しないように指示され、プラグインコードで厳密に型指定された構文を使用できるようになります。プロパティの名前解決は実行時に行われ、渡されたオブジェクトにそのようなプロパティがない場合は、例外がスローされます。

var o = new { FirstName = "John", LastName = "Doe" };

var result = MyMethod(o);

string MyMethod(dynamic o)
{
    return o.FirstName + " " + o.LastName;
}

このブログ投稿で詳細を読む

12
Alex T.

この例では、匿名オブジェクトを辞書に変換します。

IDictionary<string, object> AnonymousObjectToDictionary(object propertyBag)
{
    var result = new Dictionary<string, object>();
    if (propertyBag != null)
    {
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(propertyBag))
        {
            result.Add(property.Name, property.GetValue(propertyBag));
        }
    }
    return result;
}

次のように呼び出すことができます。

AnonymousObjectToDictionary(new { foo = 11, bar = "Be happy" });
7
Pavel Chuchuva

Linqの匿名型の場合は、IEnumerableを渡すことで簡単にこれを行うことができます。

これが受信メソッドの例です

    public static void MyMethod<IEnumType>(ref IEnumerable<IEnumType> ienum)
    {
        using (DataTable dt = new DataTable())
        {
            ienum.First(ie => true).GetType().GetProperties().ToList().ForEach(pr => dt.Columns.Add(pr.Name, typeof(string))); //Parallelization not possible since DataTable columns must be in certain order

            ienum.ToList().ForEach(ie => //Parallelization not possible since DataTable rows not synchronized.
                {
                    List<object> objAdd = new List<object>();
                    ie.GetType().GetProperties().ToList().ForEach(pr => objAdd.Add(ie.GetType().InvokeMember(pr.Name, BindingFlags.GetProperty, null, ie, null))); //Parallelization not possible since DataTable columns must be in certain order
                    dt.Rows.Add(objAdd.ToArray());
                    objAdd.Clear();
                    objAdd = null;
                });
            //Do something fun with dt
        }
    }

もちろん、リフレクションを使用しているため、遅いマシンや、Tに大きなIEnumerableまたは多くのプロパティがある場合に、パフォーマンスの問題が発生する可能性があります。

3
William

こんにちは私はそれについての記事を書きました:

http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html

お役に立てば幸いです。

2

私はこれを一度だけしました。あなたができることは、リフレクションを通じて関数から期待されるパラメータを取得することです。次に、パラメーターの配列内の名前を匿名オブジェクトのキーと照合することにより、パラメーターの配列を構築できます。

:-)お役に立てば幸いです。

1
Alxandr
public static void ExAnonymousType()
{
    var nguoi = new { Ten = "Vinh", Tuoi = 20 };
    Console.WriteLine(nguoi.Ten + " " + nguoi.Tuoi);
    DoSomeThing(nguoi);

}

private static void DoSomeThing(object nguoi)
{
    Console.WriteLine(nguoi.GetType().GetProperty("Ten").GetValue(nguoi,null));
}
1
jvinhit

C#7.0ではタプルを使用できます。 https://docs.Microsoft.com/en-us/dotnet/csharp/tuples

次に例を示します。

TestMetchod(("String 1", 342));

private void TestMetchod((string Param1, int Param2) p)
{
    //do something
}

お役に立てば幸いです。

0
SzymonB

まず最初に、System.Addin名前空間を確認してください。

次に、特定のメソッド名とパラメーターを使用して独自のインターフェースを作成し、プラグインにインターフェースを実装させることができます。プラグインプロジェクトは、アプリケーションとプラグインプロジェクトの両方で参照できる別のプロジェクトで定義できます。

0
Akash Kava