Синтаксис С# для применения действия к изменяющемуся количеству объектов - программирование

Синтаксис С# для применения действия к изменяющемуся количеству объектов

Что я хочу сделать, это комбинировать лямбда-синтаксис с "параметрами" для выполнения действия над серией объектов.

Скажем, я хочу сделать кучу элементов управления невидимыми.

После небольшого ворча я закончил метод расширения:

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" действительно может быть лучшим подходом в конце концов!

4b9b3361

Ответ 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;

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