首页 > 解决方案 > 以不同的顺序对集合中的对象执行几种方法

问题描述

我的应用程序中的用户可以决定为对象集合执行哪些活动以及以什么顺序执行。顺序在所有对象的开头(一次)设置。

用户选择的方法应由应用程序以正确的顺序执行。

例如,我定义了动作列表:

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...
        }
    }
}

请忽略任何不准确之处。

此解决方案有效。但是,“切换”指令非常大。我有几十个这样的动作。这可能不是最好的解决方案。

我认为最好的解决方案是为每个对象“MyAction”指明适当的方法(委托):

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

我不知道如何实现它(或类似的解决方案)。我希望我的代码在以后的版本中是透明和简单的。

标签: c#collectionsforeach

解决方案


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);
    }
}

诀窍是使用接受 a作为参数的Action<MyObjects>委托。MyObjects这允许您指定调用此对象上的方法的 lambda 表达式。如果需要,您甚至可以将参数传递给此类方法:

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它不会调用从依次调用的 lambda 表达式创建的委托,而是Console.WriteLine直接调用。(注意,我假设您已覆盖ToStringin MyObjects,否则只会打印类型名称。)

另请参阅:Lambda 表达式(C# 编程指南)


推荐阅读