Синтаксис С# для применения действия к изменяющемуся количеству объектов
Что я хочу сделать, это комбинировать лямбда-синтаксис с "параметрами" для выполнения действия над серией объектов.
Скажем, я хочу сделать кучу элементов управления невидимыми.
После небольшого ворча я закончил метод расширения:
public static void On<T>(this Action<T> actionToCarryOut,params T[] listOfThings)
{
foreach (var thing in listOfThings)
{
actionToCarryOut(thing);
}
}
а затем я могу создать действие:
Action<Control> makeInvisible = c => c.Visible = false;
а затем назовите его:
makeInvisible.On(control1,control2, control3,control4);
Это не очень хороший синтаксис, хотя - он чувствует себя ужасно неуклюжим.
Я могу создать метод "Применить" в базовом классе:
protected void Apply<T>(Action<T> action, params T[] appliedTo)
{
foreach (var item in appliedTo)
{
action(item);
}
}
а затем вызовите его следующим образом:
Apply<Control>(
c => c.Visible = false,
control1,
control2,
control3,);
Но это означает повторение метода в каждом базовом классе, в котором он мне нужен, и я теряю преимущество вывода типа.
Есть ли менее неуклюжий способ сделать это?
Изменить:
Самый приятный метод, который я видел до сих пор, - это плавный подход, который (с несколькими настройками) позволил бы мне написать:
Apply.Method((Control c) => c.Visible = false).To(
control1,
control2,
control3,
control4};
Это 91 символ, по сравнению с 107 для использования простого "foreach". Это заставляет меня поверить, что "foreach" действительно может быть лучшим подходом в конце концов!
Ответы
Ответ 1
Почему бы просто не называть его как обычный статический метод вместо расширения?
public static class Apply
{
public static void To<T>(this Action<T> actionToCarryOut,params T[] listOfThings)
{
foreach (var thing in listOfThings)
{
actionToCarryOut(thing);
}
}
}
Затем назовите его следующим образом:
Apply.To<Control>(c => c.Visible = false,control1,control2, control3,control4);
ИЗМЕНИТЬ
Здесь версия, использующая синтаксис Fluent:
public class Apply<T>
{
private Action<T> _action;
public Apply(Action<T> action) { _action = action; }
public static Apply<T> Method(Action<T> actionToCarryOut)
{
return new Apply<T>(actionToCarryOut);
}
public void To(params T[] listOfThings)
{
foreach (var thing in listOfThings)
{
_action(thing);
}
}
}
Использование:
Apply<Control>.Method(c => c.Visible = false).To(control1,control2, control3,control4);
Ответ 2
Вместо этого вы можете использовать метод расширения:
static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
foreach (var item in items)
{
action(item);
}
}
И затем назовите его так:
new Control[] { control1, control2, control3 }.ForEach(makeInvisible);
Или просто
new Control[] { control1, control2, control3 }.ForEach(x => x.Visible = false);
Если control1..n
- все одного типа, вы можете опустить базовый класс:
new[] { control1, control2, control3 }.ForEach(x => x.Visible = false);
Ответ 3
Возможно, вы хотите использовать более OO-подход, создав набор объектов, а затем вызовите метод на этом наборе:
new[] { control1, control2, control3 }.ForEach(x => x.Visible = false);
Функция расширения ForEach определена в наборе инструментов LinqKit.
Ответ 4
В качестве альтернативы вы можете просто сделать,
control1.Visible = false;
control2.Visible = false;
control3.Visible = false;
control4.Visible = false;
Это меньше строк кода и будет работать быстрее. Однако, если вы хотите, чтобы расширение для случая было менее тривиальным, чем одно в вашем примере, как насчет.
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach(var t in source)
{
action(t);
}
}
Тогда вы могли бы немного переработать свой оригинал, как
public static void Act<T>(Action<T> action, params T[] targets)
{
targets.ForEach(action);
}
позволяя,
Act(ctl => ctl.Visible = false, control1, control2, control3, control4);
но я бы предложил
var controls = new[] { control1, control2, control3, control4 };
foreach (var control in controls)
{
control.Visible = false;
}
является более читаемым, чем любой из методов расширения, или если вы положили его на одну строку, его очень знакомы.
foreach (var control in new[] { control1, control2, control3, control4 })
control.Visible = false;
Я думаю, что эти последние примеры демонстрируют, почему это, казалось бы, полезное расширение не допускается из фреймворка.