2010-04-21 5 views
2

Я хотел бы иметь функцию, которая может «обернуть» любой другой вызов функции. В этом конкретном случае это позволило бы мне написать более общую обработку транзакций вокруг некоторых конкретных операций.Использование дженериков в dotnet для функций с любым количеством аргументов?

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

Public Shared Sub WrapFunc(Of T)(ByVal f As Action(Of T), ByVal arg As T) 
    ' Test some stuff, start transaction 
    f(arg) 
    ' Test some stuff, end transaction 
End Sub 

... но я надеялся, чтобы это обрабатывать любое количество аргументов, без необходимости иметь дублированный код 0 аргументов, 1 ARG, 2 арг и т.д.

Есть способ сделать это?

[Изменить] Спасибо Роберту Фрейзеру за код C#. Для справки, вот перевод на VB:

[Edit2] Исправленный код. К сожалению, похоже, что нет возможности использовать отдельные функции ActAsFunc в vb. С положительной стороны, они скрыты от кого-либо, использующего закрытие, и закрытия можно использовать повторно.

Public Shared Sub WrapFunc(ByVal f As Action) 
    _WrapFunc(f) 
End Sub 
Public Shared Sub WrapFunc(Of T1)(ByVal f As Action(Of T1), ByVal arg1 As T1) 
    _WrapFunc(Closure(f, arg1)) 
End Sub 
Public Shared Sub WrapFunc(Of T1, T2)(ByVal f As Action(Of T1, T2), ByVal arg1 As T1, ByVal arg2 As T2) 
    _WrapFunc(Closure(f, arg1, arg2)) 
End Sub 

Private Shared Sub _WrapFunc(ByVal f As Action) 
    ' Test some stuff, start transaction 
    f() 
    ' Test some stuff, end transaction 
End Sub 

Private Shared Function Closure(Of T1)(ByVal f As Action(Of T1), ByVal arg1 As T1) As Action 
    Return New Action(Function() _ActAsFunc(f, arg1)) 
End Function 
Private Shared Function Closure(Of T1, T2)(ByVal f As Action(Of T1, T2), ByVal arg1 As T1, ByVal arg2 As T2) As Action 
    Return New Action(Function() _ActAsFunc(f, arg1, arg2)) 
End Function 

Private Shared Function _ActAsFunc(Of T1)(ByVal f As Action(Of T1), ByVal arg1 As T1) As Object 
    f(arg1) : Return Nothing 
End Function 
Private Shared Function _ActAsFunc(Of T1, T2)(ByVal f As Action(Of T1, T2), ByVal arg1 As T1, ByVal arg2 As T2) As Object 
    f(arg1, arg2) : Return Nothing 
End Function 

ответ

2

Nope. Хотелось бы также, чтобы это было; Я делаю это все время.

Внутренне MS использует текстовые шаблоны/инструменты генерации кода для генерации повторяющегося кода. Параметр в C# заключается в создании замыканий вокруг аргументов, а затем просто передает их в другую функцию как без аргумента System.Action; Я не уверен, поддерживает ли VB.NET это.

Вот что я делаю в C#; надеюсь, кто-то с опытом VB.NET можно перевести так:

public void add(Action action, EventFlags flags) { addInternal(action, flags); } 
public void add<T1>(Action<T1> action, T1 p1, EventFlags flags) { addInternal(closure(action, p1), flags); } 
public void add<T1, T2>(Action<T1, T2> action, T1 p1, T2 p2, EventFlags flags) { addInternal(closure(action, p1, p2), flags); } 
public void add<T1, T2, T3>(Action<T1, T2, T3> action, T1 p1, T2 p2, T3 p3, EventFlags flags) { addInternal(closure(action, p1, p2, p3), flags); } 
public void add<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 p1, T2 p2, T3 p3, T4 p4, EventFlags flags) { addInternal(closure(action, p1, p2, p3, p4), flags); } 

private static Action closure<T1>(Action<T1> action, T1 p1) { return() => action(p1); } 
private static Action closure<T1, T2>(Action<T1, T2> action, T1 p1, T2 p2) { return() => action(p1, p2); } 
private static Action closure<T1, T2, T3>(Action<T1, T2, T3> action, T1 p1, T2 p2, T3 p3) { return() => action(p1, p2, p3); } 
private static Action closure<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 p1, T2 p2, T3 p3, T4 p4) { return() => action(p1, p2, p3, p4); } 
+0

Неполадка в том, что у меня голова вокруг закрытий на данный момент, но это, безусловно, выглядит очень перспективным! Я не против делать отдельные объявления функций, если они все одни лайнеры. Я определенно займусь этим дальше. – Zarigani

+0

Получив прошлое мое первоначальное заблуждение, что «закрытие» было своего рода встроенным, я зашел в тупик при переводе «return() => action (p1)» на vb. Согласно документам «Visual Basic требует, чтобы выражение лямбда возвращало значение. В результате делегат Action не может использоваться с выражением лямбда в Visual Basic». Может ли это замыкание без этого? – Zarigani

+0

Обнаружил путь вокруг него. Спасибо за вашу помощь. – Zarigani

0

Я не пробовал это с дженериков, но как насчет ParamArray?

Public Shared Sub WrapFunc(Of T)(ByVal f As Action(Of T()), ByVal ParamArray args() As T) 
    ' Test some stuff, start transaction 
    f(args) 
    ' Test some stuff, end transaction 
End Sub 
+0

Строка «f (args)» является компиляционной ошибкой в ​​этом случае. f - Action (Of T), а не Action (Of LotsOfT), к сожалению. – Zarigani

+0

@ Заригани - Ах, хорошо. Итак, что, если вы используете Action (Of T())? Разве это не сработает? (Я только что обновил код) –

+0

Да, Action (Of T()) работает, но только если все его аргументы всегда будут одного и того же типа, и все действия принимают массив (или paramarray) в качестве аргумента. Я не знаю, как это сделать. – adam0101

0

Вы не можете использовать ParamArray?

Public Shared Sub WrapFunc(Of T)(ByVal f As Action(Of T), ByVal ParamArray args() As T) 
     ' Test some stuff, start transaction 
     For Each arg As T In args 
      f(arg) 
     Next 

     ' Test some stuff, end transaction 
    End Sub 
+0

Это вызовет одну и ту же функцию снова и снова с различными параметрами.Не требуется многопараметрическая функция, подобная OP. –

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