传递要针对具体实现列表执行的 Action<interface>

Passing an Action<interface> to to be executed against list of concrete implementations

所以我有这个

public interface ITask
{
    void PrintName(string props);
    void PrintState();
}

public class Epic: ITask
{
    public Epic() { }
    public void PrintName(string props)
    {
        Console.WriteLine("Hello Epic: " + props);
    }
    public void PrintState(string props)
    {
        Console.WriteLine("Epic Started");
    }
}


public class Story: ITask
{
    public Story() { }
    public void PrintName(string props)
    {
        Console.WriteLine("Hello Story: " + props);
    }
    public void PrintState(string props)
    {
        Console.WriteLine("Story Started");
    }
}

public class TaskProxy : ITask
{
    List<ITask> list;
    public TaskProxy (List<ITask> list) 
    { 
        this.list = list;
    }
    public void PrintName(string props)
    {            
      foreach(ITask tsk in list)
      {
        tsk.PrintName(props);
      }
    }
    public void PrintState()
    {            
      foreach(ITask tsk in list)
      {
        tsk.PrintState();
      }
    }
}

我执行的是

class Program
{
    static List<ITask> list = new List<ITask>();

    static void Main(string[] args)
    {
        list.Add(new Story());
        list.Add(new Epic());

        ITask task = TaskProxy(list );
        task.PrintName("some props")
        task.PrintState()
    }
}

但我希望将其重写为 Action<> 泛型,它将在不同实现的上下文中执行所有类似的方法。 (类似于方法借用?)

public class TaskProxy : ITask
{
    List<ITask> list;
    public TaskProxy (List<ITask> list) 
    { 
        this.list = list;
    }

    public void PrintName(string props)
    {            
       Generic(ITask.PrintName(props)) // looking for something like this    
    }

    public void PrintState()
    {            
       Generic(ITask.PrintState())  // looking for something like this   
    }

    public void Generic(Action methodToExecute)
    {            
       foreach(ITask tsk in list)
       {
          tsk.methodToExecute();
       }
    }
}

为了您的目的,反思将是一种可行的方法。解决方案可能如下所示:

using System;
using System.Collections.Generic;
using System.Reflection;

namespace CsharpPlayground
{

    public class Code
    {
        interface ITask
        {
            void printName();
        }
        class Story : ITask
        {
            public void printName()
            {
                Console.WriteLine("Story");
            }
        }
        class Epic : ITask
        {
            public void printName()
            {
                Console.WriteLine("Epic");
            }
        }

        public static void Main(string[] args)
        {
            var tasks = new List<ITask>
            {
                new Story(),
                new Epic()
            };

            // Approach 1
            Console.WriteLine("Approach 1");
            foreach (var task in tasks)
            {
                task.printName();
            }

            // Approach 2
            Console.WriteLine("\nApproach 2");
            void GenericExecuted(MethodInfo method)
            {
                foreach (ITask tsk in tasks)
                {
                    method?.Invoke(tsk, new object[0]);
                }
            }
            var printMethod = typeof(ITask).GetMethod(nameof(ITask.printName));
            GenericExecuted(printMethod);
        }
    }

}

通用变体可能如下所示:

public void Generic(Action<ITask> iTaskMethodToExecute)
{            
    foreach(ITask tsk in list)
    {
        iTaskMethodToExecute(tsk);
    }
}

说明:Action<ITask>表示以ITask为参数的动作。这允许您在 lambda 表达式中访问 ITask 提供的所有方法。

你会这样称呼它:

List<ITask> list = new List<ITask>();

list.Add(new Story());
list.Add(new Epic());

TaskProxy task = new TaskProxy(list );
task.Generic(x => x.PrintName("some props"));
task.Generic(x => x.PrintState());

乍一看,将 ITask 作为参数插入到操作中可能有点令人困惑,如下所示:

iTaskMethodToExecute(tsk);

但是如果你看一下 lambda 表达式调用:

task.Generic(x => x.PrintState());
             ^
             |
         input of type: ITask

它应该是有意义的,因为只有这样编译器才能推断出类型,intelisense 甚至会建议自动完成中的方法: