Делегувати з параметрами ... як параметр

У мене є цей метод з його делегатом, який використовується для додавання тексту до багаторядкового TextBox в графічному інтерфейсі з будь-якого з потоків у моєму додатку WinForms:

private delegate void TextAppendDelegate(TextBox txt, string text);
public void TextAppend(TextBox txt, string text)
{
  if(txt.InvokeRequired)
    txt.Invoke(new TextAppendDelegate(TextAppend), new object[] {txt, text });
  else
  {
    if(txt.Lines.Length == 1000)
    {
      txt.SelectionStart = 0;
      txt.SelectionLength = txt.Text.IndexOf("\n", 0) + 1;
      txt.SelectedText = "";
    }
    txt.AppendText(text + "\n");
    txt.ScrollToCaret();
  }
}

Це чудово працює, я просто називаю TextAppend (myTextBox1, "Hi Worldo!") З будь-якої теми, і GUI оновлюється. Чи існує якийсь спосіб передачі делегата, який викликає TextAppend до одного з моїх утиліт методів в іншому проекті, не відсилаючи ніяких посилань на фактичний TextBox, щось, що може виглядати так, як це від абонента:

Utilities.myUtilityMethod(
    new delegate(string str){ TextAppend(myTextBox1, str) });

І називається визначення, подібне до:

public static void myUtilityMethod(delegate del)
{
    if(del != null) { del("Hi Worldo!"); }
}

Таким чином, коли ця функція викликається, вона викликає метод TextAppend з цим рядком та попередньо визначеним TextBox, який хоче використати абонента. Чи можливо це чи я божевільний? Я знаю, що є прості варіанти, такі як використання інтерфейсів або передавання TextBox і делегування, але я хочу вивчити це рішення, оскільки він виглядає більш елегантним і приховує речі від назви. Проблема полягає в тому, що я все ще дуже новачок в C# і навряд чи розумію делегатів, тому, будь ласка, допоможіть мені з фактичним синтаксисом, який би працював.

Спасибі заздалегідь!

5
Пара питань, щоб краще зрозуміти ваші вимоги. Як ви очікуєте свого myUtilityMethod , щоб дізнатись, що він повинен передати єдиний рядок у ваш делегат? І як ви очікуєте, що він отримає рядок для передачі?
додано Автор Enigmativity, джерело
Ви не можете просто перемістити весь метод TextAppend у свій клас утиліти, а потім виконати Utility.TextAppend (MyTextbox, "foo") від абонента?
додано Автор Dylan Smith, джерело
@RRuiz, якщо ви переміщаєте TextAppend у клас Utility, вам не потрібно передавати делегат, оскільки TextAppend його створить. Ви просто передаєте посилання на текстове поле та рядок, який ви хочете додати. звучить як ідеальне використання комутаційного методу для мене (я б, ймовірно, зробив це методом розширення в класі TextBox).
додано Автор Dylan Smith, джерело
Яка версія .NET/C #?
додано Автор Platinum Azure, джерело
@ Platinum Azure Версія 3.5
додано Автор R. Ruiz., джерело
@Dylan Smith Я хотів би не перемістити метод у утиліту, тому тоді мені доведеться передавати посилання на свій TextBox, а також делегувати моєму методу TextAppend, щоб утиліта могла оновити GUI. Це просте рішення, так, але я хотів би мати щось більш захищене
додано Автор R. Ruiz., джерело
@Enigmativity Це хороше запитання, і я поняття не маю. Може бути, параметр у утиліті має бути таким: public static void myUtilityMethod (delegate (string) del) ????? Це те, що я не знаю, і я сподіваюсь, що деякі з вас люб'язно це пояснять
додано Автор R. Ruiz., джерело
@Dylan Smith Дякую, я знаю, що це більш пряме рішення (і, ймовірно, більш читабельний і підтримуваний), але я не хотів перемістити метод у клас Utility, оскільки його вже викликали з декількох пунктів у програмі, і мені довелося внесіть цю незначну зміну в усі ці місця, додаючи назву класу Utility перед кожним дзвінком. Крім того, я неприємний і не люблю будь-який метод за межами класу Form, щоб отримати посилання на елементи графічного інтерфейсу користувача. Фактично, я не хотів це робити в першу чергу, але потрібно було друкувати матеріал у графічному інтерфейсі іншого класу в іншому проекті.
додано Автор R. Ruiz., джерело

1 Відповіді

Якщо ви використовуєте C# 3 (VS2008) або пізнішу версію:

Utilities.myUtilityMethod(str => TextAppend(myTextBox1, str));

...

public static void myUtilityMethod(Action textAppender)
{
    if (textAppender != null) { textAppender("Hi Worldo!"); }
}

Якщо ви використовуєте .NET 2.0, ви можете використовувати анонімний метод замість лямбда-виразу:

Utilities.myUtilityMethod(delegate(string str) { TextAppend(myTextBox1, str); });

Якщо ви використовуєте .NET 1.x, вам слід визначити делегат самостійно та використовувати іменований метод:

delegate void TextAppender(string str);

void AppendToTextBox1(string str)
{
    TextAppend(myTextBox1, str);
}

...

Utilities.myUtilityMethod(new TextAppender(AppendToTextBox1));

...

public static void myUtilityMethod(TextAppender textAppender)
{
    if (textAppender != null) { textAppender("Hi Worldo!"); }
}
13
додано
Чудово! Я протестував як лямбда, так і анонімний метод, і вони працюють бездоганно. Навіть нульова умова працює, якщо я не хочу виконувати жодних дій. Велике спасибі!
додано Автор R. Ruiz., джерело
var chat = new Chat();
var chat = new Chat();
642 учасників

Обсуждение вопросов по C# / .NET / .NET Core / .NET Standard / Azure Сообщества-организаторы: — @itkpi — @dncuug