只有当DLL可用时才使用库

本文关键字:DLL | 更新日期: 2023-09-27 18:13:01

我在我的一些库中使用NLog,我希望我的库能够工作,即使我的用户NLog dll

到目前为止,我的解决方案是为我正在使用的类创建一个ILogger接口,并在发现NLog dll时使用反射从NLog调用方法。

问题是这种方法有时很慢,在我的情况下会导致CPU使用率增加~10%(有一些地方我做了很多日志记录)。

是否有更通用的解决方案来解决我的问题?也许可以使用emit,这样就不会对性能造成影响?看来这个问题应该有一个简单的解决办法。

只有当DLL可用时才使用库

我认为你的解决方案是唯一可能的,那就是使用反射。实际上,就计算而言,反射的代价更高。

我的解决方案与LogLib类似(如pepo发布的)。

我的解决方案的反射部分导致速度变慢,所以我最终使用linq表达式创建了所有日志记录器方法的编译版本。通过这种方式,我在启动时的执行时间略有增加,但在整个程序运行期间(有时以天为单位)的执行时间更快。

新版本(更快):

/// <summary>
/// Creates a method with one parameter of type TParam
/// </summary>
private static Action<object, TParam> CreateMethod<TParam>(Type targetType, string methodName)
{
    MethodInfo methodInfo = targetType.GetMethod(methodName, new Type[] { typeof(TParam) });
    ParameterExpression instance = Expression.Parameter(typeof(object), "inst");
    ParameterExpression msg = Expression.Parameter(typeof(TParam), "p");
    Expression callExpression = Expression.Call(
        Expression.Convert(instance, targetType),
        methodInfo,
        msg);
    Expression<Action<object, TParam>> methodExpression = Expression.Lambda<Action<object, TParam>>(callExpression, instance, msg);
    Action<object, TParam> method = methodExpression.Compile();
    return method;
}
/// <summary>
/// Creates a getter with the return type TReturn
/// </summary>
private static Func<object, TReturn> CreateGetter<TReturn>(Type targetType, string propertyName)
{
    PropertyInfo propertyInfo = targetType.GetProperty(propertyName);
    ParameterExpression instance = Expression.Parameter(typeof(object), "inst");
    Expression callExpression = Expression.Property(
        Expression.Convert(instance, targetType),
        propertyInfo);
    Expression<Func<object, TReturn>> methodExpression = Expression.Lambda<Func<object, TReturn>>(callExpression, instance);
    Func<object, TReturn> property = methodExpression.Compile();
    return property;
}

使用这种帮助,我存储方法的编译版本:

Action<object, string> trace = CreateMethod<string>(logger.GetType(), "Trace");
Func<object, bool> isTraceEnabled = CreateGetter<bool>(logger.GetType(), "IsTraceEnabled");

在我的包装器中,我这样调用方法:

isTraceEnabled(logger);
trace(logger, "message")

这比旧版本要复杂得多,在旧版本中,我只需将记录器声明为动态

dynamic logger = ....
// ...
logger.IsTraceEnabled;
logger.Trace("message");

但是在我的特殊情况下,加速是明显的。现在只有1%左右的减速。我做了更多的测量,结果发现这背后的实际原因是检查Trace是否启用的调用次数太多了。在发布版本跟踪被关闭,但我仍然有大约14记录器谁的IsTraceEnabled属性,我必须不断探测。

事后看来,我本可以缓存IsEnabled属性的值并获得类似的启动,但是……我注意到有点晚了

相关文章:
  • 没有找到相关文章