выглядит некрасиво, но работает.Если бы C # поддерживал динамический для статических членов, это могло бы быть лучше, но теперь мы можем использовать отражение только для вызова статического метода.
private static readonly MethodInfo LogMethod = typeof( LogEnumerableRequestAttribute ).GetMethod( nameof( Log_ ), BindingFlags.NonPublic | BindingFlags.Static );
public static IEnumerable Log(IEnumerable enumerable, Func<Stopwatch> logEntry, Action<Stopwatch> logExit, Action<Exception> logError) {
var @interface = enumerable.GetType().GetInterfaces().First( i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof( IEnumerable<> ) );
var generic = @interface.GetGenericArguments().First();
var method = LogMethod.MakeGenericMethod( generic );
return (IEnumerable) method.Invoke( null, new object[] { enumerable, logEntry, logExit, logError } );
}
private static IEnumerable<T> Log_<T>(IEnumerable<T> enumerable, Func<Stopwatch> logEntry, Action<Stopwatch> logExit, Action<Exception> logError) {
var stopwatch = logEntry();
try {
using (var enumerator = enumerable.GetEnumerator()) {
while (MoveNext( enumerator, logError )) yield return enumerator.Current;
}
} finally {
logExit( stopwatch );
}
}
private static bool MoveNext<T>(IEnumerator<T> enumerator, Action<Exception> logError) {
try {
return enumerator.MoveNext();
} catch (Exception ex) {
logError( ex );
throw;
}
}