使用Serilog解构开放泛型

4

是否有可能根据开放式通用类型解构 Serilog 事件数据?例如,我正在尝试这样做:

.Destructure.ByTransforming<CosmosResponse<T>>(
    transform =>
        new
        {
            transform.StatusCode,
            transform.RequestCharge,
            transform.ActivityId,
        })

这是为了从任何 Cosmos 响应对象中提取应记录的特定信息。但它似乎不起作用 - 我的回调函数从未被调用。
我还尝试了调用 ByTransformingWhere 并始终返回 true。我惊讶地发现它被用于每个日志调用,而不仅仅是与 CosmosResponse<T> 相关的调用。虽然它确实为 Cosmos 响应对象调用了我的谓词,但仍未调用回调来转换对象。
更新:
到目前为止,这是我能够实现的最好效果:
.Destructure.ByTransformingWhere<dynamic>(
    t => t.IsGenericType && t.GenericTypeArguments.Length == 1 && t.IsSubclassOf(typeof(CosmosResponse<>).MakeGenericType(t.GenericTypeArguments[0])),
    r =>
        new
        {
            r.StatusCode,
            r.RequestCharge,
            r.ActivityId
        })

这有点令人担忧,因为谓词被调用每次记录调用,但是我找不到其他解决方法。

更新2

在这种情况下,一个更好的方法是完全避免解构,而是向Cosmos客户端添加自定义处理程序。这可以拦截所有请求,并且我关心的各个信息(状态代码、请求费用等)都存在于响应标头中。

当然,这只适用于Cosmos DB的客户端库,与原始问题无关。如果您实际上需要根据开放式泛型进行解构,则以上仍然是目前已知的最佳选项。

1个回答

4
我希望这样做能够完成工作:

我期望这个功能可以达到预期效果:

.Destructure.ByTransformingWhere<dynamic>(
                    t => t.GetGenericTypeDefinition() == typeof(CosmosResponse<>),
                    o => new { o.Whatever })

作为文档所述

在对对象进行析构时,如果谓词返回 true,则使用提供的函数转换指定类型的实例。请注意,要避免在谓词中进行任何密集型工作,因为它可能会显著减慢流水线。

因此,最好看看如何优化或避免那些 Reflection 调用。

更新

为了具有适当的智能提示/类型检查,您应该能够执行:

.Destructure.ByTransformingWhere<CosmosResponse<object>>(
    t => t.IsGenericType && t.GenericTypeArguments.Length == 1 && t.IsSubclassOf(typeof(CosmosResponse<>).MakeGenericType(t.GenericTypeArguments[0])),
    r =>
        new
        {
            r.StatusCode,
            r.RequestCharge,
            r.ActivityId
        })
(即,提供CosmosResponse<object>作为类型参数,而不是dynamic,以便存在于CosmosResponse上的属性可以亮起来)

谢谢 - 我已经更新了我的问题,并提供了我找到的解决方案。希望在实际应用中不会有什么问题。 - Kent Boogaart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接