Как создать в C # метод, принимающий метод в качестве параметра, имеющий неопределенное количество параметров? - PullRequest
1 голос
/ 08 ноября 2019

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

public void MyMethod (some_generic_method)

То, что "some_generic_method" может иметь различное количество параметров с однородными типами данных. Как мне создать подпись «MyMethod»?

Редактировать: Я постараюсь объяснить как можно яснее, зачем запрашиваемое решение. Я делаю тестовую библиотеку в C #, и библиотека включает в себя метод, похожий на «MyMethod».

Представьте себе:

  • пользователь создал класс, который имеет несколько различных методов,
  • пользователь "использует" мою библиотеку в своем скрипте C #,
  • пользователь заранее знает, что для возможности использования библиотеки имена его методов должны содержать конкретную строку (предположим, «test»),
  • моя библиотека «MyMethod»должен найти те пользовательские методы, которые содержат «test» как часть их имен (в соответствующей части моего кода я использую Reflection, assembly, type, ... и «if (method.name содержит« test »)«чтобы библиотека могла определять эти конкретные методы и передавать их в свой« MyMethod »по отдельности),
  • Теперь, поскольку мы не знаем, как выглядят эти пользовательские сигнатуры методов, параметр« MyMethod »должно быть таким образом, чтобы он мог обрабатывать любой пользовательский метод. Вот почему в моем вопросе, в первую очередь, я упомянул, что «some_generic_method» (который является параметром «MyMethod») может иметь разное количество параметров с однородными / гетерогенными типами данных.

Я надеюсь, что это объяснение делаетуточнение вопроса.

Спасибо.

Ответы [ 3 ]

2 голосов
/ 09 ноября 2019

Рассмотрение

Насколько я знаю, невозможно вызвать метод, не зная его сигнатуры.

И в C # это не похоже на Javascript или Python илиНапример, в Ruby сигнатура является статической, окончательно определенной после компиляции, поэтому неизменной.

Даже используя отражение объекта в качестве параметра, у вас будет та же проблема, что и для управления параметрами этого неизвестного метода, имеющего неизвестные параметры неизвестногоtypes.

C # - это язык со строгим типом, скомпилированный язык, даже с использованием динамики.

C # Обобщения не означают, наоборот, неизвестные типы и сигнатуры, и онине шаблоны C ++, даже если это предки.

Использование params для параметров

https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/params

public delegate void ParameterizedActionWithParams(params object[] parameters);

public void MyAction(ParameterizedActionWithParams action, params object[] parameters)
{
  if ( action != null )
    action(parameters);
  else
    ManageArgumentNullException();
}

Использование спискаобъектов

public delegate void ParameterizedActionWithList(List<object> parameters);

public void MyAction(ParameterizedActionWithList action, List<object> parameters)
{
  if ( action != null )
    action(parameters);
  else
    ManageArgumentNullException();
}

Ограничения

Вы не можете иметь строго типизированные аргументы.

И если вам нужны функции, то естьпроблема, если возвращаемый параметр можетварьируются, и вы можете сделать только:

public delegate object ParameterizedFuncWithParams(params object[] parameters);

public delegate object ParameterizedFuncWithList(List<object> parameters);

Поэтому вам нужно создать следующие варианты:

public object MyFunc(ParameterizedFuncWithParams func, params object[] parameters)
{
  if ( func != null )
    return func(parameters);
  else
    ManageArgumentNullException();
}

public object MyFunc(ParameterizedFuncWithList func, List<object> parameters)
{
  if ( func != null )
    return func(parameters);
  else
    ManageArgumentNullException();
}
1 голос
/ 08 ноября 2019

То, что "some_generic_method" может иметь различное количество параметров с однородными типами данных.

Ограничение "однородных типов данных" очень помогает. Мы можем определить наш новый метод с помощью одного аргумента типа:

public void MyMethod<T>(...)

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

public void MyMethod<T>(Func<T> arg) { ... }
public void MyMethod<T>(Func<T,T> arg) { ... }
public void MyMethod<T>(Func<T,T,T> arg) { ... } 
// etc

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

Но мне интересно, не могли бы вы настроить что-то подобное:

public void MyMethod<T>(Func<IEnumerable<T>,T> arg) { ... }
public void MyMethod<T>(Func<T[],T> arg) { ... } 
1 голос
/ 08 ноября 2019

Если вы будете делать это достаточно долго, вы в конечном итоге будете писать эту функцию снова и снова:

    public static Type3 CombineFunc1AndFunc2(
   Func<Type1, Type2> func1,
   Func<Type2, Type3>> func2,
   Type1 input)
    {
   return func2(func1(input))
   }

Подобные функции-обертки не имеют особого смысла, когда они специализированы для одного типа. ,Однако, если вы введете некоторые переменные типа и опустите входной параметр, то ваше определение GetFormattedRate будет выглядеть так:имеет мало цели. Это не универсальный, поэтому вы должны дублировать этот код повсюду. Это усложняет ваш код, потому что теперь ваш код должен собирать все, что ему нужно, из тысячи крошечных функций самостоятельно. Однако ваше сердце находится в нужном месте: вам просто нужно привыкнуть к использованию этих видов общих функций высшего порядка для объединения вещей. Или используйте старую добрую лямбда-моду, чтобы превратить Func и A в Func

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