Метод передачи в качестве параметра с использованием С#

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

public int Method1(string)
{
    ... do something
    return myInt;
}

public int Method2(string)
{
    ... do something different
    return myInt;
}

public bool RunTheMethod([Method Name passed in here] myMethodName)
{
    ... do stuff
    int i = myMethodName("My String");
    ... do more stuff
    return true;
}

public bool Test()
{
    return RunTheMethod(Method1);
}

Этот код не работает, но это то, что я пытаюсь сделать. Я не понимаю, как написать код RunTheMethod, так как мне нужно определить параметр.

Ответ 1

Вы можете использовать делегат Func в .net 3.5 в качестве параметра в вашем методе RunTheMethod. Делегат Func позволяет указать метод, который принимает несколько параметров определенного типа и возвращает один аргумент определенного типа. Вот пример, который должен работать:

public class Class1
{
    public int Method1(string input)
    {
        //... do something
        return 0;
    }

    public int Method2(string input)
    {
        //... do something different
        return 1;
    }

    public bool RunTheMethod(Func<string, int> myMethodName)
    {
        //... do stuff
        int i = myMethodName("My String");
        //... do more stuff
        return true;
    }

    public bool Test()
    {
        return RunTheMethod(Method1);
    }
}

Ответ 2

Вам нужно использовать делегат. В этом случае все ваши методы принимают параметр string и возвращают int - это наиболее просто представлено делегатом Func<string, int> 1. Таким образом, ваш код может стать правильным с таким простым изменением, как это:

public bool RunTheMethod(Func<string, int> myMethodName)
{
    // ... do stuff
    int i = myMethodName("My String");
    // ... do more stuff
    return true;
}

Делегаты обладают гораздо большей властью, чем это, по общему признанию. Например, с С# вы можете создать делегат из выражения лямбда, чтобы вы могли вызвать ваш метод таким образом:

RunTheMethod(x => x.Length);

Это создаст анонимную функцию:

// The <> in the name make it "unspeakable" - you can't refer to this method directly
// in your own code.
private static int <>_HiddenMethod_<>(string x)
{
    return x.Length;
}

а затем передайте этот делегат методу RunTheMethod.

Вы можете использовать делегаты для подписки на события, асинхронное выполнение, обратные вызовы - всевозможные вещи. Это стоит прочитать на них, особенно если вы хотите использовать LINQ. У меня есть article, который в основном касается различий между делегатами и событиями, но в любом случае вы можете найти его полезным.


1 Это основано только на общий тип делегата Func<T, TResult> в структуре; вы можете легко заявить о себе:

public delegate int MyDelegateType(string value)

а затем сделайте вместо этого параметр MyDelegateType.

Ответ 3

Из примера OP:

 public static int Method1(string mystring)
 {
      return 1;
 }

 public static int Method2(string mystring)
 {
     return 2;
 }

Вы можете попробовать Action Delegate! А затем вызвать ваш метод с помощью

 public bool RunTheMethod(Action myMethodName)
 {
      myMethodName();   // note: the return value got discarded
      return true;
 }

RunTheMethod(() => Method1("MyString1"));

Или же

public static object InvokeMethod(Delegate method, params object[] args)
{
     return method.DynamicInvoke(args);
}

Тогда просто вызовите метод

Console.WriteLine(InvokeMethod(new Func<string,int>(Method1), "MyString1"));

Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));

Ответ 4

public static T Runner<T>(Func<T> funcToRun)
{
    //Do stuff before running function as normal
    return funcToRun();
}

Использование:

var ReturnValue = Runner(() => GetUser(99));

Ответ 5

Вы должны использовать делегат Func<string, int>, представляющий функцию, принимающую аргумент string в качестве аргумента и возвращающий int:

public bool RunTheMethod(Func<string, int> myMethod) {
    // do stuff
    myMethod.Invoke("My String");
    // do stuff
    return true;
}

Затем используйте его:

public bool Test() {
    return RunTheMethod(Method1);
}

Ответ 6

Чтобы поделиться как можно более полным решением, я собираюсь представить три различных способа работы, но теперь я собираюсь начать с самого основного принципа.


Краткое введение

Все языки CLR (Common Language Runtime) (такие как С# и Visual Basic) работают в виртуальной машине под названием CLI (Common Language Interpreter), которая выполняет код на более высоком уровне, чем родные языки, такие как C и C++ (которые напрямую компилируются в машину). код). Из этого следует, что методы - это не какой-либо вид скомпилированного блока, а просто структурированные элементы, которые CLR распознает и использует для извлечения своего тела и передачи его встроенным инструкциям машинного кода. Таким образом, вы не можете думать о том, чтобы передать метод в качестве параметра, потому что метод сам по себе не создает никакого значения: это не допустимое выражение! Таким образом, вы собираетесь запутаться в концепции делегата.


Что за делегат?

Делегат представляет указатель на метод. Как я уже говорил выше, метод не является значением, поэтому в языках CLR существует специальный класс, Delegate, который объединяет любой метод, который может быть неявно приведен к тому, который имеет ту же сигнатуру.

Посмотрите на следующий пример использования:

static void MyMethod()
{
    Console.WriteLine("I was called by the Delegate special class!");
}

static void CallAnyMethod(Delegate yourMethod)
{
    yourMethod.DynamicInvoke(new object[] { /*Array of arguments to pass*/ });
}

static void Main()
{
    CallAnyMethod(MyMethod);
}

Три способа:

  • Способ 1
    Используйте специальный класс Delegate напрямую, как в примере выше. Проблема этого решения заключается в том, что ваш код не будет проверяться при динамической передаче аргументов, не ограничивая их типами, указанными в определении метода.

  • Путь 2/3 Помимо специального класса Delegate, концепция делегатов распространяется на пользовательские делегаты, которые являются определениями методов, которым предшествует ключевое слово delegate, и ведут себя так же, как обычные методы. Следовательно, они проверены, и вы получите "безопасный" код.

Посмотрите на следующий пример:

delegate void PrintDelegate(string prompt);

static void PrintSomewhere(PrintDelegate print, string prompt)
{
    print(prompt);
}

static void PrintOnConsole(string prompt)
{
    Console.WriteLine(prompt);
}

static void PrintOnScreen(string prompt)
{
    MessageBox.Show(prompt);
}

static void Main()
{
    PrintSomewhere(PrintOnConsole, "Press a key to get a message");
    Console.Read();
    PrintSomewhere(PrintOnScreen, "Hello world");
}

Второй вариант не писать свой собственный пользовательский делегат - использовать один из них, уже определенный в рамках:

  • Action завершает void без аргументов.
  • Action<T1> завершает void одним аргументом.
  • Action<T1, T2> завершает void двумя аргументами.
  • И так далее...
  • Func<TR> оборачивает функцию с типом возвращаемого значения TR и без аргументов.
  • Func<T1, TR> оборачивает функцию с типом возвращаемого значения TR и одним аргументом.
  • Func<T1, T2, TR> оборачивает функцию с типом возвращаемого значения TR и двумя аргументами.
  • И так далее...

(Последнее решение - то, которое большинство людей отправило.)

Ответ 7

Если вы хотите изменить метод, который вызывается во время выполнения, я бы рекомендовал использовать делегат: http://www.codeproject.com/KB/cs/delegates_step1.aspx

Это позволит вам создать объект для хранения метода для вызова, и вы можете передать его другим методам, когда это необходимо.

Ответ 8

Хотя принятый ответ абсолютно правильный, я хотел бы предоставить дополнительный метод.

Я оказался здесь после того, как сделал свой собственный поиск решения аналогичного вопроса. Я создаю фреймворк, подключенный к плагину, и, как часть его, я хотел, чтобы люди могли добавлять пункты меню в меню приложений в общий список, не подвергая действительный объект Menu, потому что инфраструктура может развертываться на других платформах, t имеют объекты Menu UI. Добавление общей информации о меню достаточно просто, но разрешение разработчику плагина достаточной свободы для создания обратного вызова при нажатии на меню оказалось болью. Пока меня не стало, что я пытался заново изобрести колесо и обычное меню вызова и вызвать обратный вызов из событий!

Итак, решение, столь же простое, как кажется, когда вы это осознаете, ускользало от меня до сих пор.

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

Ответ 9

Вот пример, который поможет вам лучше понять, как передать функцию в качестве параметра.

Предположим, что у вас есть родительская страница, и вы хотите открыть всплывающее окно для ребенка. На родительской странице есть текстовое поле, которое должно быть заполнено на основе всплывающего текстового поля.

Здесь вам нужно создать делегат.

Parent.cs      // декларация делегатов      public delegate void FillName (String FirstName);

Теперь создайте функцию, которая заполнит ваше текстовое поле, а функция должна отображать делегаты

//parameters
public void Getname(String ThisName)
{
     txtname.Text=ThisName;
}

Теперь при нажатии кнопки вам нужно открыть всплывающее окно Child.

  private void button1_Click(object sender, RoutedEventArgs e)
  {
        ChildPopUp p = new ChildPopUp (Getname) //pass function name in its constructor

         p.Show();

    }

В конструкторе ChildPopUp вам необходимо создать параметр "тип делегирования" родительской//страницы

ChildPopUp.cs

    public  Parent.FillName obj;
    public PopUp(Parent.FillName objTMP)//parameter as deligate type
    {
        obj = objTMP;
        InitializeComponent();
    }



   private void OKButton_Click(object sender, RoutedEventArgs e)
    {


        obj(txtFirstName.Text); 
        // Getname() function will call automatically here
        this.DialogResult = true;
    }

Ответ 11

Если вы хотите передать метод в качестве параметра, используйте:

using System;

public void Method1()
{
    CallingMethod(CalledMethod);
}

public void CallingMethod(Action method)
{
    method();   // This will call the method that has been passed as parameter
}

public void CalledMethod()
{
    Console.WriteLine("This method is called by passing parameter");
}

Ответ 12

class PersonDB
{
  string[] list = { "John", "Sam", "Dave" };
  public void Process(ProcessPersonDelegate f)
  {
    foreach(string s in list) f(s);
  }
}

Второй класс - это Клиент, который будет использовать класс хранения. У него есть метод Main, который создает экземпляр PersonDB, и он вызывает этот объект Process с методом, определенным в классе Client.

class Client
{
  static void Main()
  {
    PersonDB p = new PersonDB();
    p.Process(PrintName);
  }
  static void PrintName(string name)
  {
    System.Console.WriteLine(name);
  }
}