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

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

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, так как мне нужно определить параметр.

10 ответов


вы можете использовать делегат 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);
    }
}

вам нужно использовать делегат. В этом случае все ваши методы принимают .


вы также можете попробовать делегат action!

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

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

 public bool RunTheMethod(Action myMethodName)
 {
      myMethodName();
      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"));

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

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

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

вы должны использовать 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);
}

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

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


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

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

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


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


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

все CLR (Среда CLR) языки (такие как C# и Visual Basic) работают под виртуальной машиной с именем CLI (Переводчик Общего Языка), который запускает код на более высоком уровне, чем родные языки, такие как 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<TR, T1> обертывает функцию с помощью TR возвращаемый тип и с одним аргументом.
  • Func<TR, T1, T2> обертывает функцию с TR возвращаемый тип и с двумя аргументами.
  • и так далее...

(последнее решение заключается в том, что многие люди в курсе.)


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

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

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

родитель.цезий // заявление делегатов public delegate void FillName (String FirstName);

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

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

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

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

         p.Show();

    }

в конструкторе ChildPopUp вам нужно создать параметр "тип делегата" родительского / / page

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

вот пример без параметра: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string

с params: http://www.daniweb.com/forums/thread98148.html#

вы в основном передаете массив объектов вместе с именем метода. затем вы используете оба метода вызова.

параметр params объекта[] параметры