postsharp - PostSharp:如何装饰返回的 IEnumerable?
问题描述
如何让它工作?
public override void OnExit(MethodExecutionArgs args) {
var enumerable = (IEnumerable) args.ReturnValue;
return Log(
enumerable, // How to cast to unknown generic type?
() => logger.LogRequestEntry(),
stopwatch => logger.LogRequestExit( stopwatch ),
ex => logger.LogRequestError( ex ) );
}
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;
}
}
解决方案
它看起来很难看,但它有效。如果 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;
}
}
推荐阅读
- python - scrapy 可以根据 id 提交输入吗?
- javascript - 无法将 unicode 标志添加到正则表达式以进行电子邮件检查
- java - 转义字符串中的流氓反斜杠
- string - 如何在单个函数中接受 &str、String 和 &String?
- javascript - 无法在 knockoutJS 视图模型中映射 .json 数据
- apache-camel - 如何从 Apache Camel 中的 Azure 事件中心读取数据
- pdf - PDF 自定义属性值中是否存在不安全字符?
- docker - Docker-Compose ParserError:解析块映射时
- python - 为什么我的 tkinter 代码在调用函数 [python3] 后停止运行?
- android - 如何使用背景颜色不等于 colorPrimary