Передача анонимного типа в качестве параметров метода - PullRequest
22 голосов
/ 08 августа 2010

В моей архитектуре плагина я в настоящее время передаю имя плагина (строка), имя метода (строка) и параметры (массив объектов) моей службе плагина, чтобы выполнить указанный метод и вернуть результат (типа 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, но я предпочитаю определять свои параметры в методе плагина, а не принимать один динамический объект.

Спасибо, Бен

[Обновление]

После просмотра ASPИсходный код .NET MVC кажется достаточно простым, чтобы вытянуть анонимный тип в словарь объектов, например RouteValueDictionary.С помощью отражения выражение linq создается динамически.Несмотря на то, что это хорошая реализация, я не хотел, чтобы все эти дополнительные сложности были такими.

Согласно приведенному ниже комментарию, я могу добиться читабельности, просто указав свои параметры inline (нет необходимости в объявлении массива объектов):

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

Ответы [ 9 ]

21 голосов
/ 07 сентября 2010

Я в конце концов наткнулся на этот пост , который демонстрирует использование анонимных типов в качестве словарей. Используя этот метод, вы можете передать анонимный тип как параметр метода (объект) и получить доступ к его свойствам.

Однако я бы также добавил, что после изучения новых динамических функций в .net 4.0, таких как ExpandoObject, становится намного чище передавать динамический объект в качестве параметра:

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

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

        public static void SayHello(dynamic properties)
        {
           Console.WriteLine(properties.FirstName + " " + properties.LastName);
        }
12 голосов
/ 06 ноября 2011

Используйте динамический объект для параметров, если вы хотите передать анонимный тип.Метод execute плагина должен ожидать определенных свойств объекта параметра, чтобы работать.При использовании динамического ключевого слова C # компилятор получит указание не выполнять проверку типа параметра и позволит использовать строго типизированный синтаксис в коде плагина.Разрешение имени свойства будет происходить во время выполнения, и если переданный объект не имел таких свойств, будет выдано исключение.

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

var result = MyMethod(o);

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

Подробнее в этом сообщении в блоге

9 голосов
/ 08 августа 2010

Есть несколько способов сделать это возможным, хотя я бы не советовал ни одному из них.

Во-первых, вы можете использовать отражение, что означает, что вы должны написать много дополнительного (подверженного ошибкам) ​​кода в вашем методе PluginService.Execute, чтобы получить нужные значения.

Во-вторых, если вы знаете параметры анонимного типа, передаваемого вашему методу, вы можете использовать метод, описанный здесь . Вы можете привести к другому анонимному типу внутри вашего метода, который имеет те же свойства. Здесь - другое описание той же техники от Джона Скита.

В-третьих, вы можете использовать классы из System.ComponentModel. Например, ASP.NET MVC использует это. Использует отражение под капотом. Однако в ASP.NET MVC либо имена свойств хорошо известны (например, controller и action), либо их имена не имеют значения, поскольку они передаются как есть в метод контроллера (например, id). ).

7 голосов
/ 13 августа 2012

Этот пример преобразует анонимный объект в словарь:

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" });
3 голосов
/ 25 сентября 2012

Если это автономный тип от 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
        }
    }

Конечно, поскольку выиспользуя рефлексию, вы можете увидеть проблемы с производительностью на более медленных машинах или когда у вас есть большой IEnumerable или множество свойств в T.

2 голосов
/ 23 июня 2011

Привет, я написал пост об этом:

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

Надеюсь, это поможет.

1 голос
/ 08 июля 2014
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 голос
/ 08 августа 2010

Я сделал это один раз. Что вы можете сделать, это получить параметры, ожидаемые от функции через отражение. Затем вы можете создать свой массив параметров, сопоставив имена в массиве параметров с ключами анонимного объекта.

Надеюсь, это поможет :-).

0 голосов
/ 08 августа 2010

Прежде всего, проверьте пространство имен System.Addin, там вы можете получить некоторую помощь.

Во-вторых, вы можете создать собственный интерфейс с определенными именем и параметрами метода и позволить плагину реализовать интерфейс,Вы можете определить интерфейс плагина в другом проекте, на который можно ссылаться как в приложении, так и в проекте плагина.

...