Dreagen Dreagen - 3 months ago 18
C# Question

dynamic keyword with builder pattern hides extension method

I have recently come across a strange behavior with the

dynamic
keyword whilst I was testing something. This isn't a problem I desperately need solving as I was just experimenting, but I was wondering if anyone could shed any light on what was happening

I have a builder which returns an
HttpWebRequest
object and an extension method on
HttpWebRequest
.

One of my builder methods takes a
string
argument. The whole thing works when I pass the builder method a string, but I pass it a
dynamic
variable which is a string it no longer works.

It appears as if the builders method which should return type
HttpWebRequestBuilder
now returns
dynamic
.

The code below is a simple was to reproduce it and is also available here

Note

To make it work, comment out the line
.SetBody(dynamicString)
and uncomment the line
.SetBody(json)
.

public class Program
{
public static void Main()
{
dynamic dynamicString = "{ \"test\" : \"value\" }";
string json = "{ \"test\" : \"value\" }";

string test = new HttpWebRequestBuilder()
.SetRequestType()
//.SetBody(json) //uncomment this and it works
.SetBody(dynamicString) //uncomment this and it breaks
.Build()
.ExtensionMethod();

Console.WriteLine(test);
}

}

public class HttpWebRequestBuilder
{
private readonly HttpWebRequest _request;

public HttpWebRequestBuilder()
{
Uri uri = new Uri("http://www.google.com");
_request = WebRequest.CreateHttp(uri);
}

public HttpWebRequestBuilder SetRequestType()
{
_request.Method = "POST";
_request.ContentType = "application/json";

return this;
}

public HttpWebRequestBuilder SetBody(string json)
{
byte[] bytes = Encoding.UTF8.GetBytes(json);
_request.ContentLength = bytes.Length;

using (Stream writer = _request.GetRequestStream())
{
writer.Write(bytes, 0, bytes.Length);
writer.Flush();
}

return this;
}

public HttpWebRequest Build()
{
return _request;
}
}

public static class WebRequestExtensions
{
public static string ExtensionMethod(this HttpWebRequest webRequest)
{
return "extension method worked";
}
}


I'm guessing this is something strange with the way
dynamic
objects work. But any explanation would be greatly appreciated

Answer

This happens because passing a dynamic parameter makes C# compiler treat the return type of the expression, i.e. .SetBody(dynamicString), as dynamic (relevant explanation of method return types with dynamic parameters).

Extension methods work with dynamic objects only as regular methods, not as extension methods (see Eric Lippert's answer for an explanation of this), hence the compile-time error that you see.

Comments