仅在DLL可用时才使用库

时间:2015-09-16 07:41:17

标签: c# dll proxy nlog

我在我的一些库中使用 NLog ,即使我的用户没有 NLog dll,我也希望我的库能够工作/强>

到目前为止,我的解决方案是为我正在使用的类创建一个ILogger接口,如果找到了NLog dll,则使用反射从NLog调用方法。

问题是这种方法有时非常慢,导致我的CPU使用率增加了~10%(有些地方我做了大量的日志记录)。

我的问题是否有更通用的解决方案?也许使用发射使我没有这样的性能打击?似乎应该有一个简单的解决方案来解决这个问题。

2 个答案:

答案 0 :(得分:0)

我认为您的解决方案是唯一可行的,即使用反射。 实际上,反射在计算方面更加昂贵。

答案 1 :(得分:0)

我的解决方案与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是否启用的极端调用次数。在发布版本中,Trace已关闭,但我仍然有大约14个记录器,我必须经常探测IsTraceEnabled属性。

事后我可以缓存IsEnabled属性的值并获得类似的启动,但是哦......我注意到它有点迟了。