Выполнение в различном порядке нескольких методов на предметах в коллекции - PullRequest
0 голосов
/ 29 июня 2019

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

Методы, выбранные пользователем, должны выполняться приложением в правильном порядке.

Например, я определил списокactions:

this.ActionsList = new List<MyAction>
{
    new MyAction {Id = "123", Order = 1, Text = "Method 5", IsActive = true},
    new MyAction {Id = "abc", Order = 5, Text = "Method 1", IsActive = false},
    new MyAction {Id = "def", Order = 3, Text = "Method 3", IsActive = true}
};

У меня также есть коллекция объектов:

var myObjects = new List<MyObjects>();

Теперь для каждого объекта в коллекции программа должна вызывать методы, связанные с активированными действиями.Определенное действие определяет, какой метод будет вызван.

foreach (var o in myObjects){

    var actions = ActionsList.Where(x => x.IsActive).OrderBy(x => x.Order);

    foreach (var a in ActionsList){
        switch(a.Id){
            case "123":
                o.Method5();
                break;
            case "abc":
                o.Method1();
                break;
            // etc...
        }
    }
}

Пожалуйста, игнорируйте любые неточности.

Это решение работает.Однако инструкция «switch» очень велика.У меня есть десятки таких действий.Это, вероятно, не лучшее решение.

Я думаю, что лучшим решением было бы указать соответствующий метод (делегаты) для каждого объекта «MyAction»:

new MyAction {Id = "def", Order = 3, Text = "Method 3", IsActive = true, 
MethodToCallDelegate = Method3}

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

1 Ответ

2 голосов
/ 29 июня 2019

Вы можете добавить делегата в класс MyAction

public Action<MyObjects> Action { get; set; }

Список действий затем можно инициализировать следующим образом:

this.ActionsList = new List<MyAction> {
   new MyAction { Order = 1, Text = "Method 5", Action = o => o.Method5(), IsActive = true },
   new MyAction { Order = 5, Text = "Method 1", Action = o => o.Method1(), IsActive = false },
   new MyAction { Order = 3, Text = "Method 3", Action = o => o.Method3(), IsActive = true }
};

И действия можно применять следующим образом.

var orderedActions = ActionsList
    .Where(a => a.IsActive)
    .OrderBy(a => a.Order)
    .ToList();
foreach (MyObjects o in myObjects) {
    foreach (MyAction action in orderedActions) {
        action.Action(o);
    }
}

Хитрость заключается в использовании делегата Action<MyObjects>, принимающего MyObjects в качестве параметра.Это позволяет вам указать лямбда-выражение, которое вызывает метод для этого объекта.Вы даже можете передать параметры таким методам, если требуется:

Action = o => o.StringMethod1("Hello")
Action = o => o.StringMethod2("Hello", "World")

или сделать совершенно разные вещи

Action = o => o.Text = "okay"
Action = o => Console.WriteLine(o)
Action = o => { o.Text = "statement lambda"; Console.WriteLine(o); }

Делегат остается тем же, потому что у него всегда есть один параметр MyObjects,

В особом случае, когда вы хотите вызвать метод, совместимый с делегатом Action<MyObjects>, вы можете передать сам метод в качестве делегата.Вы опускаете фигурные скобки параметра, чтобы указать, что вы не хотите вызывать его здесь.

Action = Console.WriteLine

Это будет иметь тот же эффект, что и o => Console.WriteLine(o), но будет более эффективным.Вместо вызова делегата, созданного из лямбда-выражения, которое, в свою очередь, вызывает Console.WriteLine, он будет вызывать Console.WriteLine напрямую.(Обратите внимание, я предполагаю, что вы переопределили ToString в MyObjects, в противном случае будет напечатано только имя типа.)

См. Также: Лямбда-выражения (Руководство по программированию в C #) *

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