2010-06-16 2 views
0

Возможно, я потерял участок, но, надеюсь, кто-то может указать мне в правильном направлении.Generic Func <> как параметр к базовому методу

Что я пытаюсь сделать?

Я пытаюсь написать некоторые базовые методы, которые принимают Func <> и действие, чтобы эти методы обрабатывали всю обработку исключений и т. Д., Поэтому его не повторяли повсюду, но позволяли производным классам определять, какие действия он выполняет хочет выполнить.

До сих пор это базовый класс.

public abstract class ServiceBase<T> 
{ 
    protected T Settings { get; set; } 

    protected ServiceBase(T setting) 
    { 
     Settings = setting; 
    } 

    public void ExecAction(Action action) 
    { 
     try 
     { 
      action(); 
     } 
     catch (Exception exception) 
     { 
      throw new Exception(exception.Message); 
     } 
    } 

    public TResult ExecFunc<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function) 
    { 
     try 
     { 
      /* what goes here?! */ 
     } 
     catch (Exception exception) 
     { 
      throw new Exception(exception.Message); 
     } 
    } 
} 

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

public void Delete(string application, string key) 
{ 
    ExecAction(() => Settings.Delete(application, key)); 
} 

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

Я хочу, чтобы быть в состоянии назвать это следующим образом (если это возможно):

public object Get(string application, string key, int? expiration) 
{ 
    return ExecFunc(() => Settings.Get(application, key, expiration)); 
} 

Могу ли я думать слишком сумасшедшим или же это возможно? Заранее благодарим за помощь.

+0

Я не понимаю. Ваши обработчики исключений восстанавливают исключения, но без трассировки стека? – Amy

+0

В качестве побочного примечания, 'throw new Exception', вероятно, здесь неправильно. По крайней мере, вы хотите увлечь «ex» как внутреннее исключение. Другой вариант - «throw», чтобы повторно выбросить его, не перезагружая стек, или просто не поймать его, если вы ничего не делаете с ним. – Kobi

+0

Спасибо за ответы, не беспокойтесь о том, что обработка исключений будет обновлена. Это было просто для примера :-) – WestDiscGolf

ответ

3
public void Delete(string application, string key) 
{ 
    ExecAction(() => Settings.Delete(application, key)); 
} 

public object Get(string application, string key, int? expiration) 
{ 
    return ExecFunc(() => Settings.Get(application, key, expiration)); 
} 

// ... 

public TResult ExecFunc<TResult>(Func<TResult> func) 
{ 
    try 
    { 
     return func(); 
    } 
    catch (Exception exception) 
    { 
     throw new Exception(exception.Message); 
    } 
} 

Кстати, ваша обработка исключений выглядит немного хитроумный: Во-первых, это не считается хорошей практикой, чтобы поймать Exception себя , Вместо этого подумайте о том, чтобы уловить более конкретные исключения. Во-вторых, вы бросаете новое исключение в свой блок catch, а это означает, что вы теряете стек и т. Д. Из исходного исключения. Вместо этого вы должны использовать throw;, чтобы восстановить исходное исключение. (Это предполагает, что ваш блок catch выполняет какую-то полезную работу. Если все, что вы делаете, это ловить и метать, то просто полностью удаляйте блоки try...catch.)

+0

Спасибо за ответ; сработал. Я знал, что пропустил что-то в своих предыдущих попытках до публикации. Я согласен с тем, что обработка исключений выглядит хитроумной, она была просто введена на начальном этапе разработки, это будет разобрано :-) – WestDiscGolf

1
public TResult ExecFunc<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function, T1 t1Param, T2 t2Param, T3 t3Param) 
{ 
    try 
    { 
     return function(t1Param, t2Param, t3Param); 
    } 
    catch (Exception exception) 
    { 
     throw new Exception(exception.Message); 
    } 
} 

Тогда вы называете это так:

public object Get(string application, string key, int? expiration) 
{ 
    return ExecFunc(Settings.Get, application, key, expiration); 
} 
0
public object Get(string application, string key, int? expiration) 
{ 
    object result = null; 
    ExecAction(() => result = Settings.Get(application, key, expiration)); 
    return result 
} 
4

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

Но как правило, что вы делаете, вы уже решили проблему с Action. Для удобства вам просто необходимо уточнение для Func, вызывающую версию Action:

public static TResult ExecFunc<TResult>(Func<TResult> func) 
{ 
    TResult result = default(TResult); 
    ExecAction(() => result = func()); 
    return result; 
} 

Там нет необходимости, чтобы обеспечить способ передачи аргументов через, потому что закрытие уже решить эту проблему:

var someData = "Hi!"; 
var result = ExecFunc(() => SomeOtherMethod(someData)); 
// the lambda can close over the local variables of the outer scope 

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

+0

Спасибо за ответ; +1 интересное повторное использование функциональности ExecAction :-) Что касается обработки исключений, это будет исправлено, она была добавлена ​​только для начальной фазы dev. Его рядом можно исправить. – WestDiscGolf

+1

Прохладный - вот почему полезно вызывать 'ExecFunc' вызов' ExecAction', поэтому, когда вы меняете код упаковки, вам нужно сделать это только один раз. :) –

Смежные вопросы