Метод с вводом метода Var?

#c#

#c#

Вопрос:

В C#:

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

Позвольте мне более подробное описание:

Я хочу метод с сигнатурой

 bool IsDoit(var method)
{
    try
    {
        method(...);
        return true;
    }
    catch{return false;}
}
  

Это возвращает метод и логическое значение, которое вызывает исключение или нет!

Универсальный делегат? Общее действие? Общая функция?

У вас есть какие-либо идеи или это невозможно?

Комментарии:

1. Вместо bool возвращать объект исключения — лучшая идея

Ответ №1:

Что должно входить в «…» здесь? Похоже, вам нужен делегат с некоторым описанием — и сигнатура этого делегата должна соответствовать сигнатуре метода, который вы хотите вызвать. Например:

 static bool IsDoit(Action method)
{
    try
    {
        method();
        return true;
    }
    catch
    {
        return false;
    }
}
  

Это позволит преобразовать группу методов для любого метода void без параметров:

 if (IsDoIt(SomeMethodWithNoParameters))
{
}
  

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

 if (IsDoIt(() => MethodWithParameters("first", "second"))
{
}
  

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

Комментарии:

1. Я согласен с вами по поводу перехвата исключений и их проглатывания. Спасибо за вашу идею.

2. @RedHat: За исключением того, что это Exception уже ссылочный тип, поэтому вы не можете писать Nullable<Exception> . Но я бы все равно обычно не поощрял это; идиоматический способ обработки исключений заключается в том, чтобы они выбрасывались, а не возвращались. Могут быть некоторые случаи, когда это уместно, но я бы предположил, что они довольно редки.

Ответ №2:

Да, для методов без параметров замените var на Action .

Ответ №3:

Вы можете передать свой метод как делегат, например, с помощью action:

 bool IsDoit(Action test)
{
   test(...);
} 
  

Ответ №4:

Вы всегда можете принять универсальный делегат. Все делегаты являются производными от System.Делегировать

 using System;

public class Program
{
    public delegate R Deleg1<R,T1>(T1 arg);
    public delegate R Deleg2<R,T1,T2>(T1 arg1, T2 arg2);
    public delegate R Deleg3<R,T1,T2,T3>(T1 arg1, T2 arg2, T3 arg3);

    public static void AcceptAny<R,T1>(Deleg1<R,T1> del) {  /**/ }
    public static void AcceptAny<R,T1,T2>(Deleg2<R,T1,T2> del) {  /**/ }
    public static void AcceptAny<R,T1,T2,T3>(Deleg3<R,T1,T2,T3> del) {  /**/ }

    public static void Main(string[] args)
    {
    }
}
  

Если вы не возражаете против небольшого удаления текста, вы можете

 public delegate R DelegParams<R>(params object[] @params);
public static void AcceptAny<R>(DelegParams<R> paramsFunc) {  /**/ }
  

Вы можете косвенно назначить практически любой делегат для этой подписи, используя для ее переноса лямбда-выражение (очень похоже на Action подход, показанный Джоном Скитом).

Обратите внимание, что делегаты используют общий базовый класс и позволяют вызывать их с использованием интерфейсов, подобных отражению (например, используя общие object[] параметры): Delegate.Метод DynamicInvoke