0

I am passing a handler function as an argument to another function. One of the arguments of the handler is a dynamic object and I am accessing one of its properties.

Here is an example:

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

And here is how the handler gets invoked:

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

This worked well. Then I shuffled some things around and it broke. The dynamic object comes in as expected with all of its properties but now timed?.name throws Microsoft.CSharp.RuntimeBinder.RuntimeBinderException exception complaining that the object does not have a definition of property name.

I looked at these answers for a solution:

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

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

and the following works:

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

(Get properties of a Dynamic Type)

but I am not sure why direct access stopped working. Any ideas? Thank you!

1 Answer 1

2

I discovered the reason it broke. Initially, both the handler and the function the handler is passed in belonged to the same assembly. After the refactoring the handler and the object invoking it were split into different projects and namespaces thus preventing the binding at compile time.

The solution was to no longer pass a dynamic but a serialized object:

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

and then consume it as:

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

        _logger.Write(operation.name);
    }

Decoupling thus requires the extra step of serialization but allows for more reuse of the code.

Sign up to request clarification or add additional context in comments.

1 Comment

This looks like a major code smell. Why was the parameter defined as a dynamic type in the first place? Why not define a class having Name, Dto, and Request properties and use that? That way you can have the compiler check that you are accessing properties that actually exist.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.