#c# #lambda #interface #delegates #func
Вопрос:
Итак, у меня есть это
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 { Listlt;ITaskgt; list; public TaskProxy (Listlt;ITaskgt; 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 Listlt;ITaskgt; list = new Listlt;ITaskgt;(); static void Main(string[] args) { list.Add(new Story()); list.Add(new Epic()); ITask task = TaskProxy(list ); task.PrintName("some props") task.PrintState() } }
Но я хочу, чтобы вместо этого это было переписано как Actionlt;gt; generic, которое будет выполнять все аналогичные методы в контексте другой реализации. (что-то вроде заимствования метода?)
public class TaskProxy : ITask { Listlt;ITaskgt; list; public TaskProxy (Listlt;ITaskgt; 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(); } } }
Комментарии:
1. Мне действительно непонятно, что ты пытаешься сделать. Чего бы вы ожидали от
Funclt;gt;
возвращения? Вы действительно ищете анActionlt;ITaskgt;
? (Функция возвращает что-то, действие-нет.) В качестве примечания я настоятельно рекомендую вам следовать обычным соглашениям об именах при написании примеров кода, подобных этому,-это позволяет избежать отвлекающих читателей.2. Даже теперь, когда вы перешли к действию (в теле — вам все еще нужно написать название), неясно, что вы пытаетесь сделать. Вы можете принять
Actionlt;ITaskgt;
и позвонитьaction(tsk);
по каждому пункту в списке… Хотя я не совсем понимаю, почему вы ожидаете, что сможете позвонитьtsk.action()
…3. Извините, у меня есть IInterfaceProxyImplementation, который выполняет все методы интерфейса по сравнению со всеми другими реализациями IInterface в цикле. попытка избежать цикла в каждой интерфейсной реализации IInterfaceProxyImplementation путем создания универсальных методов. Постараюсь быть более ясным в следующий раз
4. Нет, пожалуйста, на этот раз выразитесь яснее. Я сильно подозреваю, что если вы не отредактируете свой вопрос, чтобы прояснить его, вы не получите ответа. (Конечно, у меня недостаточно информации, чтобы ответить на этот вопрос.) Вы все еще хотите получить ответ на этот вопрос? Для начала было бы целесообразно определить интерфейс с несколькими методами, если речь идет о возможности выполнения нескольких методов…
5. @JonSkeet, надеюсь, на этот раз все будет более ясно
Ответ №1:
Общий вариант может выглядеть следующим образом:
public void Generic(Actionlt;ITaskgt; iTaskMethodToExecute) { foreach(ITask tsk in list) { iTaskMethodToExecute(tsk); } }
Пояснение: Actionlt;ITaskgt;
означает действие, которое принимает ITask
параметр as. Это позволяет получить доступ в лямбда-выражении ко всем методам, которые предоставляет ITask.
Вы бы назвали это тогда так:
Listlt;ITaskgt; list = new Listlt;ITaskgt;(); list.Add(new Story()); list.Add(new Epic()); TaskProxy task = new TaskProxy(list ); task.Generic(x =gt; x.PrintName("some props")); task.Generic(x =gt; x.PrintState());
На первый взгляд может показаться немного запутанным вставлять ITask
параметр as в действие, как в этой строке:
iTaskMethodToExecute(tsk);
Но если вы посмотрите на вызов лямбда-выражения:
task.Generic(x =gt; x.PrintState()); ^ | input of type: ITask
это должно иметь смысл, потому что только так компилятор сможет определить тип, и intelisense предложит даже методы автозаполнения:
Комментарии:
1. Именно то, что мне нужно ! Большое вам спасибо! если у вас есть какие-либо хорошие учебные пособия по улучшению моих дженериков , я был бы вам признателен.
2. @Dexters Я рад, что смог помочь. к сожалению, учебные пособия по концентрации ничего не приходит на ум так быстро.
Ответ №2:
Для вашей цели размышление было бы жизнеспособным подходом. Решение может выглядеть следующим образом:
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 Listlt;ITaskgt; { 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); } } }
Комментарии:
1. Спасибо, 2 — й подход-это то, что я пытался сделать, но пытался избежать размышлений.