Подтвердить что ты не робот

Передача анонимного типа в качестве параметров метода

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

Ответ 1

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

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

Во-вторых, если вы знаете параметры анонимного типа, которые вы передаете в свой метод, вы можете использовать описанную ниже технику здесь. Вы можете использовать другой метод анонимного типа, который имеет те же свойства. Здесь - это еще одно описание того же метода от Jon Skeet.

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

Ответ 2

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

Однако я бы также добавил, что после изучения новых динамических функций в .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);
        }

Ответ 3

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

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

var result = MyMethod(o);

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

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

Ответ 4

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

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" });

Ответ 5

Если он является автономным типом из 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.

Ответ 7

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

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

Ответ 8

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));
}

Ответ 9

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

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