C # Шаблон для кеширования действий, принимающих общие параметры - PullRequest
3 голосов
/ 09 декабря 2011

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

private Dictionary<String, Action<Drawing, String>> actions = new Dictionary<String,  Action<Drawing, String>>();
private void LoadActions()
{
     actions.Add("Height", (d, s) => d.Height = Double.Parse(s));
     actions.Add("Width", (d, s) => d.Width = Double.Parse(s));
}
private void ProcessDrawing(Drawing drawing, String prop, String value)
{
     actions[prop](drawing, value);
}

Проблема, с которой я столкнулся, заключается в том, что класс Drawing является общим (Drawing<T>), поэтому я не могу определить действия, подобные следующим, поскольку T не определен:

Dictionary<String, Action<Drawing<T>, String>> actions = new Dictionary<String,  Action<Drawing<T>, String>>();

Без кеширования код выглядит так:

private void ProcessDrawing<T>(Drawing<T> drawing, String prop, String value)
{
     var actions = new Dictionary<String, Action<Drawing<T>, String>>();
     actions.Add("Height", (d, s) => d.Height = Double.Parse(s));
     actions.Add("Width", (d, s) => d.Width = Double.Parse(s));
     actions[prop](drawing, value);
}

Так, как я могу кэшировать кучу действий, принимающих универсальный тип параметра?

Спасибо

Ответы [ 3 ]

1 голос
/ 09 декабря 2011

Базовый класс всех действий - MulticastDelegate.Вам нужно определить ваш dict как Dictionary<String,MulticastDelegate> и использовать соответствующие приведения после извлечения ваших действий из dict.

EDIT : тесты показывают, что лямбда-выражения, очевидно, нельзя напрямую назначать переменнымтипа MulticastDelegate.Это связано с тем, что тип параметров лямбда-выражения выводится из типа переменной (или параметра метода), которой он назначен.Поэтому сначала присвойте его переменной с правильным типом Action<>.Затем присвойте это MulticastDelegate.

. В этом примере я показываю обе версии (через параметр метода и через переменную):

public static void CallTestDelegate()
{
    TestDelegate((d, s) => d.Height = Single.Parse(s));
}

public static void TestDelegate(Action<RectangleF, string> action)
{
    Dictionary<String, MulticastDelegate> dict = new Dictionary<string, MulticastDelegate>();
    dict.Add("a1", action);
    Action<RectangleF, string> action2 = (d, s) => d.Width = Single.Parse(s);
    dict.Add("a2", action2);

    var a1 = (Action<RectangleF, string>)dict["a1"];
    a1(new RectangleF(), "15");
}
0 голосов
/ 09 декабря 2011

T - это просто заполнитель, создайте абстрактный класс или интерфейс, представляющий нужные вам объекты

0 голосов
/ 09 декабря 2011

Один из вариантов - сделать Drawing<T> производным от неуниверсального интерфейса IDrawing, который имеет свойства Height и Width, а затем изменить ваши действия на тип Action<IDrawing,String>.

Другой вариант (менее безопасный для типов) - сделать ваши действия типа Action<dynamic,String>.

...