2016-05-27 7 views
1

So habe ich eine Erweiterungsmethode, die es mir erlaubt, etwas zu protokollieren, wenn eine Aktion ausgeführt wird. Die Umsetzung ist in etwa so:Gibt es eine Möglichkeit, Aktion und Aktion zu verallgemeinern <T>?

public static Action Log(this Action action, string log) { 
    return (() => { 
     Console.WriteLine(log); 
     action(); 

    }); 
} 

Aber ich will für die Aktion, damit auch ein Action<T> zu sein. Gibt es eine Möglichkeit, dies zu verallgemeinern, so dass log wird protokolliert, aber es ändert sich nicht die Signatur der Aktion?

Oder brauche ich 2 Methoden, eine für Action und eine für Action<T>?

Antwort

3

Sie benötigen separate Methoden, aber Sie ca n einer in Bezug auf die anderen implementieren, um Code-Duplizierung zu reduzieren:

Angesichts Ihrer bestehenden Log(Action action, string log), können Sie hinzufügen:

public static Action<T> Log<T>(this Action<T> action, string log) { 
    return t => Log(() => action(t), log); 
} 

Oder umgekehrt:

public static Action<T> Log(this Action<T> action, string log) { 
    return t => { 
     Console.WriteLine(log); 
     action(t); 
    }); 
} 

public static Action Log(this Action action, string log) { 
    return() => Log<object>(t => action(), log); 
} 
2

Sie benötigen zwei Methoden, da Action und Action<T> in diesem Szenario nicht miteinander kompatibel sind.

Es wäre nützlich, wenn Action eigentlich Action<void> wäre, um dieses Verhalten zu aktivieren, aber das ist nicht der Fall.

+0

Ja, Swift erlaubt tun das, als 'Void' ist ein Datentyp in sich. Ich habe mich gefragt, ob C# dies auch erlaubt. – vrwim

2

könnten Sie Typ Delegate verwenden und die Argumente für Sie Maßnahmen wie param object[] wie folgt liefern:

public static Action Log(this Delegate action, string log, params object[] args) 
{ 
    return() => 
    { 
     Console.WriteLine(log); 
     action.DynamicInvoke(args); 
    }; 
} 

Sie diese Erweiterung so verwenden können:

Action<int> testAction = i => Console.WriteLine($"Test: {i}"); 
testAction.Log("Logging", 42).Invoke(); 

Das in dieser Ausgabe führt:

Logging 
Test: 42 
+0

Oh, ich hatte den Eindruck, dass das OP wollte 'Log ' zurückgeben 'Aktion ' (was bedeutet, dass die Parameter tot der Aktion nicht an 'Log' übergeben werden) - aber das OP gab das nicht an. Sie könnten mit Ihrer Interpretation richtig liegen. – hvd

+0

Ja, das war nicht meine Absicht, ich wollte die resultierende 'Aktion' speichern und später aufrufen. Aber das ist nett +1 – vrwim

+0

Upvote, weil dies eine interessante Lösung ist, aber es beinhaltet eine Art von "dynamischen Muster". Da es sich bei C# um eine statisch typisierte Sprache handelt, ist die @ hvd-Lösung bei weitem besser. Es stimmt auch mit dem überein, was Sie in den .NET-Basis-Frameworks und den meisten verfügbaren Bibliotheken finden. –