1

I would like some explanation of you experts in C# 4.0 dynamic.

I have a fluent builder class to help configure an object before creating it. This interface has a method SetParameters(...):

    public FluentBuilder<TInterface> SetParameters(dynamic parameters)
    {
        _parameters = parameters;
        return this;
    }

I'm doing this to consume the fluent interface:

var order = new Order();

/* Setting up parameters */
dynamic parameters = new ExpandoObject();
parameters.Transaction = transactionObj;
parameters.CurrentPrincipal = Thread.CurrentPrincipal;

var proxiedOrder = ObjectProxyFactory
    .Configure<IOrder>(order)
    .FilterMethods(o => o.InsertOrder())
    .AddPreDecoration(AppConcerns.JoinSqlTransaction)
    .AddPreDecoration(AppConcerns.EnterLog)
    .AddPostDecoration(AppConcerns.ExitLog)
    .AddPostDecoration(AppConcerns.SecurityCheck)
    .SetParameters(parameters)
    .Teste() //this method doesn't exist in the fluent builder
    .CreateProxy();

var result = proxiedOrder.InsertOrder();

As commented in the above snippet, the method called Teste() doesn't exists in the fluent interface, but intelissense allow write anymethod after I call SetParameters like it returning dynamic, but as you see in code, SetParameters returns FluentInterface that is not dynamic.

The code above compiles sucessfully by in runtime will fail because in runtime the method Teste() will not be found in FluentBuilder class.

To resolve this problem in design-time, and to get correct Intelissense, I need to cast the parameter to the ExpandoObject class:

var proxiedOrder = ObjectProxyFactory
.Configure<IOrder>(order)
.FilterMethods(o => o.InsertOrder())
.AddPreDecoration(AppConcerns.JoinSqlTransaction)
.AddPreDecoration(AppConcerns.EnterLog)
.AddPostDecoration(AppConcerns.ExitLog)
.AddPostDecoration(AppConcerns.SecurityCheck)
.SetParameters((ExpandoObject)parameters) //cast to ExpandoObject
.Teste() //now intelissense is giving me an "red" error and solution will not compile
.CreateProxy();

var result = proxiedOrder.InsertOrder();

I've found that, anytime I pass a C# dynamic parameter in any method chaining, after that method receiving the dynamic parameter, the subsequent calls to methods will behave like returning a C# dynamic object, even if the return type of the method it's not dynamic.

Is it a bug ? Or is this expected to happens ?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Jone Polvora
  • 2,184
  • 1
  • 22
  • 33

1 Answers1

6

It's expected to happen. Any method call involving a dynamic argument is resolved dynamically - the exact overload can't be determined until execution time, so the return type is unknown at compile time, so it's treated as being dynamic. In some cases the C# compiler could infer more information (e.g. if it's a static method call) but for simplicity it doesn't. Only a variable few expressions involving dynamic values have non-dynamic types. (From memory, the is operator is always bool, and a constructor is always assumed to return the type being constructed.)

EDIT: I've finally found the spec reference. From section 7.6.5:

An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:

  • The primary-expression has compile-time type dynamic.
  • At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.

In this case the compiler classifies the invocation-expression as a value of type dynamic.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks for clarifying, now I know that if a method has a dynamic parameter, then by convention the result will be considered dynamic in designtime, when using method chaining. But I don't agree with this, since the method invoked has a return that the IDE can infer in design time. Why a dynamic parameter could alter the result of an method that has a return type defined? – Jone Polvora Jun 03 '12 at 21:45
  • So, yeah, we're not absolutely sure if you're chaining or not - we decided to just not give you intellisense at all GL HF – Lodewijk Jun 23 '18 at 05:43