Лучшее (общее) объявление делегатов Func - PullRequest
4 голосов
/ 23 февраля 2012

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

internal bool RemoteLogin(string password)
{
    return (bool)InvokeMethod(new Func<string, bool>(Server.RemoteLogin), password);            
}

internal string GetSessionId()
{            
    return (string)InvokeMethod(new Func<string>(Server.GetSessionId));                      
}

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

Чтобы вызвать InvokeMethod, я должен передать новый Func <....>, добавить параметр (ы) и также привести возвращаемое значение к соответствующему типу. Есть ли лучший (более общий) способ сделать это, например, используя Generics или Reflection?

Любая помощь высоко ценится.

Ответы [ 5 ]

3 голосов
/ 23 февраля 2012

Вы можете добиться определенного объема строгой типизации - за счет повторения, используя Func вариации:

public R InvokeMethod<T,R>(Func<T,R> method, T argument)
{
    return method(argument);
}   

public R InvokeMethod<T1,T2,R>(Func<T1,T2,R> method, T1 argument1, T2 argument2)
{
    return method(argument1, argument2);
}   

public R InvokeMethod<T1,T2,T3,R>(Func<T1,T2,T3,R> method, T1 argument1, T2 argument2, T3 argument3)
{
    return method(argument1, argument2, argument3);
}   

и т. Д.

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

public R InvokeMethod<R>(Func<R> method)
{
    return method();
}

, а затем вызвать его следующим образом:

internal bool RemoteLogin(string password)
{
    return InvokeMethod(() => Server.RemoteLogin(password));
}

internal string GetSessionId()
{            
    return InvokeMethod( () => Server.GetSessionId());
}

Таким образом, вы оставите обработку параметров для лямбда-выражения, и вынужно написать InvokeMethod один раз.

2 голосов
/ 23 февраля 2012

"В моем примере выше, метод InvokeMethod упрощен. В моем приложении он регистрирует, отслеживает, обрабатывает исключения и т.д. вызова."

Учитывая этот комментарий, я предлагаю изменить это. Вместо того, чтобы вызывать делегат как этот, вы могли бы заставить операцию принять Func<T>, вот так:

public T InvokeMethod<T>(Func<T> method)
{
    // Add wrapper as needed
    return method();
}

Затем вы можете вызвать его с помощью лямбды, когда вам нужно передать параметры:

internal bool RemoteLogin(string password)
{
    return InvokeMethod(() => Server.RemoteLogin(password));            
}

internal string GetSessionId()
{            
    return InvokeMethod(Server.GetSessionId);                      
}
1 голос
/ 23 февраля 2012

Дополнительная информация: Если у метода нет возвращаемого значения (например, «void Logout ()»), вы можете использовать делегат Action (у метода может быть то же имя -> InvokeMethod -> из-за другой сигнатуры / параметра):

public void InvokeMethod(Action method)
{
    method();
}
1 голос
/ 23 февраля 2012
static T Invoke<T>(Func<T> method)
{
  //Log here
  return method();
}

bool RemoteLogin(string password)
{
  return Invoke(() => Server.RemoteLogin(password));
}
1 голос
/ 23 февраля 2012

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

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

Тогда ваш звонок выше становится:

return InvokeMethod(new Func<string, bool>(Server.RemoteLogin), password);  

И тип возвращаемого значения Boolean определяется типом возвращаемого значения в вашем методе.

...