Краткий метод передачи ассоциативных массивов в метод

StackOverflow https://stackoverflow.com/questions/530782

Вопрос

Ищем способ передать ассоциативный массив методу.Я хочу переписать пакет анимации Actionscript на C#, но у меня возникли проблемы с «ассоциативными» массивами/объектами.Обычно в Actionscript я могу сделать что-то вроде:

public function tween(obj:DisplayObject, params:Object = null):void {
    if (params.ease != null) {
        //do something
    }
    //...
}

И это можно было бы назвать так:

tween(this, {ease:'out', duration:15});

Я ищу способ сделать то же самое на С#.На данный момент я собрал следующие варианты:

а) создание класса или структуры для определения возможных ключей и типов параметров и их передачи

б) передать параметры как общий тип

tween(frameworkElement, new {ease = 'out', duration = 15});

предполагая

public static void tween(FrameworkElement target, object parameters);

и найдите способ использовать это в функции анимации (я не уверен, как разделить ключ = значение для этого объекта.Любые идеи?)

в) создать Dictionary<string, object> передать параметры в функцию анимации

Есть еще идеи или пример кода?Я новичок в C#.

Редактировать

Мне потребовался целый день, чтобы понять это:

«Анонимные типы не могут использоваться совместно за пределами сборок.Компилятор гарантирует, что в каждой сборке существует не более одного анонимного типа для заданной последовательности пар имя/тип свойства.Чтобы передавать структуры между сборками, вам необходимо правильно их определить».

Это было полезно?

Решение

РЕДАКТИРОВАТЬ:По сути, это механизм, который расширения HtmlHelper используют в ASP.NET MVC.У меня это не оригинально.


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

public static void tween( FrameworkElement target, object parameters )
{
    return tween( target, new ParameterDictionary( parameters ) );
}

public static void tween( FrameworkElement target,
                          ParameterDictionary values )
{
    if (values.ContainsKey( "ease" ))
    {
      ....
    }
}

Затем у вас есть класс ParameterDictionary, который использует отражение анонимного типа и настраивает словарь.

public class ParameterDictionary : Dictionary<string,object>
{
    public ParameterDictionary( object parameters )
    {
         if (parameters != null)
         {
             foreach (PropertyInfo info in parameters.GetType()
                                                     .GetProperties())
             {
                 object value = info.GetValue(parameters,null);
                 this.Add(info.Name,value);
             }
         }
    }
}

Это дает вам как простоту использования, так и простоту потребления — «уродливые» отражения заключаются в единственный конструктор словаря, а не в ваш метод.И, конечно же, словарь можно использовать снова и снова для аналогичных целей, при этом код отражения пишется только один раз.

Другие советы

Словарь представляет собой разумный подход.Это может выглядеть так:

public static void tween(FrameworkElement target, IDictionary<string, object> parameters)
{
    if (parameters.ContainsKey("ease")) {
        //do something
    }
}

Имейте в виду, что при передаче значений вы можете использовать сокращенный синтаксис инициализации коллекции, чтобы упростить задачу, например:

tween(something, new Dictionary<string, object> { { "ease", "out" }, { duration, 15 } });

Это был бы довольно быстрый способ сделать примерно «то же самое», что и код ActionScript, но на C# он не очень хорош.Способ сделать это в стиле C# — создать настоящую структуру или класс TweenParameters со свойствами для каждого возможного параметра, а затем создать такую ​​структуру для передачи в tween().Обычно это считается более удобным в обслуживании, поскольку все «доступные» свойства очевидны для вызывающего объекта без изучения внутреннего устройства tween(), а также потому, что он улавливает ошибки во время компиляции, которые при сравнении строк не будут заметны до времени выполнения, например набираю "длительность" "дюратоин".

Я сам являюсь поклонником варианта (b) — передачи анонимного типа и анализа значений с использованием отражения.

Я видел, как другие добивались того же самого, используя лямбда-выражения.Синтаксис вызова будет следующим:

tween(frameworkElement, ease => "out", duration => 15);

И декларация будет примерно такой:

public static void tween(FrameworkElement target, params Expression<Func<object>>[] parameters) { ... }

Идея состоит в том, что вы можете взять переменное количество «функций, возвращающих объект».Затем вы анализируете имя параметра из каждого Выражение<TDelegate>, и вызовите каждый из них, чтобы получить его значение.

Я не думаю, что это лучше, чем размышления над анонимным типом, но это еще один подход, который стоит рассмотреть.

Обновлять

Я уже писал об идее передачи ассоциативных массивов в виде словарей в своем блоге. здесь и здесь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top