【问题标题】:Accessing a dynamic's property threw an exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'访问动态属性引发了“Microsoft.CSharp.RuntimeBinder.RuntimeBinderException”类型的异常
【发布时间】:2020-11-16 19:29:15
【问题描述】:

我将一个处理函数作为参数传递给另一个函数。处理程序的参数之一是一个动态对象,我正在访问它的一个属性。

这是一个例子:

    protected virtual void OnTime(dynamic timed, HttpResponseMessage response, TimeSpan time)
    {
        _logger.Write(timed?.name);
    }

下面是调用处理程序的方式:

OnTime?.Invoke(new {name = dto.name, dto, request }, httpResponseMessage, elapsed);

这很好。然后我洗了一些东西,它坏了。动态对象的所有属性都按预期出现,但现在 timed?.name 抛出 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException 异常,抱怨该对象没有属性 name 的定义。

我查看了这些答案以寻求解决方案:

Why does the assignment from a dynamic object throw a RuntimeBinderException?

Dynamic throwing Microsoft.CSharp.RuntimeBinder.RuntimeBinderException on private types

以下作品:

Dictionary<string, object> values = ((object)timed)
                                 .GetType()
                                 .GetProperties()
                                 .ToDictionary(p => p.Name, p => p.GetValue(v));

(Get properties of a Dynamic Type)

但我不确定为什么直接访问停止工作。有任何想法吗?谢谢!

【问题讨论】:

    标签: c# dynamic


    【解决方案1】:

    我发现了它坏掉的原因。最初,处理程序和传入处理程序的函数都属于同一个程序集。重构后,处理程序和调用它的对象被拆分为不同的项目和命名空间,从而防止在编译时进行绑定。

    解决方案是不再传递动态对象而是序列化对象:

    OnTime?.Invoke(JsonConvert.SerializeObject(new { name = dto.Name, dto, request }), httpResponseMessage, elapsed);
    

    然后将其消费为:

        protected virtual void OnTime(string timed, HttpResponseMessage response, TimeSpan time)
        {
            var operation = JsonConvert.DeserializeAnonymousType(timed, new { name = string.Empty });
    
            _logger.Write(operation.name);
        }
    

    因此,解耦需要额外的序列化步骤,但允许更多地重用代码。

    【讨论】:

    • 这看起来像是主要的代码异味。为什么首先将参数定义为动态类型?为什么不定义一个具有 Name、Dto 和 Request 属性的类并使用它呢?这样你就可以让编译器检查你正在访问实际存在的属性。
    猜你喜欢
    • 1970-01-01
    • 2013-01-14
    • 2013-08-28
    • 2015-07-18
    • 2011-02-14
    相关资源
    最近更新 更多