2016-08-04 15 views
6

Niedawno natknąłem się na dziwne zachowanie ze słowem kluczowym dynamic podczas testowania czegoś. Nie jest to problem, który rozpaczliwie potrzebuję rozwiązać, ponieważ właśnie eksperymentowałem, ale zastanawiałem się, czy ktoś może rzucić jakiekolwiek światło na to, co się dzieje. Mam buildera, który zwraca obiekt HttpWebRequest i metodę rozszerzenia na HttpWebRequest."dynamiczne" słowo kluczowe z ukrytym wzorcem modelu konstruktora

Jedna z moich metod konstruktora przyjmuje argument string. Cała sprawa działa, gdy przekazuję metodę budowniczego ciąg znaków, ale przekazuję mu zmienną dynamic, która jest ciągiem, który już nie działa.

Wygląda na to, że metoda budowniczych, która ma zwrócić typ HttpWebRequestBuilder, teraz zwraca dynamic.

Poniższy kod jest proste było go odtworzyć, a także jest dostępny here

Uwaga

Aby to działało, skomentuj linię .SetBody(dynamicString) i usuń linię .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"; 
    } 
} 

Zgaduję, że to jest coś dziwnego w działaniu obiektów dynamic. Ale wszelkie wyjaśnienia byłyby bardzo mile widziane.

Odpowiedz

7

Dzieje się tak, ponieważ przekazanie parametru dynamic dlatego, C# kompilator leczenia typ wartości ekspresji, to znaczy .SetBody(dynamicString) jak dynamic (odpowiedniego explanation of method return types with dynamic parameters).

Metody rozszerzeń działają z obiektami dynamic tylko jako zwykłymi metodami, a nie metodami rozszerzającymi (zobacz: Eric Lippert's answer), stąd pojawia się błąd podczas kompilacji.

+0

Czytałem, że odpowiedź Eric przeszłości, ale całkowicie zapomniał o tym:/ –

1

Chociaż odpowiedź dasblinkenlight wydaje się być w porządku, proszę pamiętać, że zawsze można uniknąć tego problemu, zmieniając swój kod w ten sposób:

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

     var test = new HttpWebRequestBuilder(); 
      test.SetRequestType(); 
      //test.SetBody(json); //still works 
      test.SetBody(dynamicString); // works also now 
      var b = test.Build(); 
      var s = b.ExtensionMethod(); 

     Console.WriteLine(s); 
    } 
} 
+0

Dzięki za to, zrobiłem coś podobnego do obejścia, kiedy testowałem. Pytanie było dla mnie bardziej zrozumiałe, dlaczego tak się dzieje. To może być pomocne dla kogoś innego, więc zrezygnuję z +1 – Dreagen