Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy is an ExpandoObject breaking code that otherwise works just fine?
    text
    copied!<p>Here's the setup: I have an Open Source project called "Massive" (github/robconery/massive) and I'm slinging around dynamics as a way of creating SQL on the fly, and dynamic result sets on the fly.</p> <p>To do the database end of things I'm using System.Data.Common and the ProviderFactory stuff. Here's a sample that works just fine (it's static so you can run in a Console):</p> <pre><code> static DbCommand CreateCommand(string sql) { return DbProviderFactories.GetFactory("System.Data.SqlClient") .CreateCommand(); } static DbConnection OpenConnection() { return DbProviderFactories.GetFactory("System.Data.SqlClient") .CreateConnection(); } public static dynamic DynamicWeirdness() { using (var conn = OpenConnection()) { var cmd = CreateCommand("SELECT * FROM Products"); cmd.Connection = conn; } Console.WriteLine("It worked!"); Console.Read(); return null; } </code></pre> <p>The result of running this code is <strong>"It worked!"</strong></p> <p>Now, if I change the string argument to dynamic - specifically an ExpandoObject (pretend that there's a routine somewhere that crunches the Expando into SQL) - a weird error is thrown. Here's the code:</p> <p><img src="https://i.stack.imgur.com/rHQBk.png" alt="Dynamic Error"></p> <p>What worked before now fails with a message that makes no sense. A SqlConnection <em>is</em> a DbConnection - moreover if you mouseover the code in debug, you can see that the types are all SQL types. "conn" is a SqlConnection, "cmd" is a SqlCommand. </p> <p>This error makes utterly no sense - but more importantly it's cause by the presence of an ExpandoObject that doesn't touch any of the implementation code. The differences between the two routines are: 1 - I've changed the argument in CreateCommand() to accept "dynamic" instead of string 2 - I've created an ExpandoObject and set a property.</p> <p>It gets weirder.</p> <p>If simply use a string instead of the ExpandoObject - it all works just fine!</p> <pre><code> //THIS WORKS static DbCommand CreateCommand(dynamic item) { return DbProviderFactories.GetFactory("System.Data.SqlClient").CreateCommand(); } static DbConnection OpenConnection() { return DbProviderFactories.GetFactory("System.Data.SqlClient").CreateConnection(); } public static dynamic DynamicWeirdness() { dynamic ex = new ExpandoObject(); ex.TableName = "Products"; using (var conn = OpenConnection()) { //use a string instead of the Expando var cmd = CreateCommand("HI THERE"); cmd.Connection = conn; } Console.WriteLine("It worked!"); Console.Read(); return null; } </code></pre> <p>If I swap out the argument for CreateCommand() to be my ExpandoObject ("ex") - it causes <em>all</em> of the code to be a "dynamic expression" which is evaluated at runtime.</p> <p>It appears that the runtime evaluation of this code is different than compile-time evaluation... which makes no sense.</p> <p>**EDIT: I should add here that if I hard-code <em>everything</em> to use SqlConnection and SqlCommand explicitly, it works :) - here's an image of what I mean:</p> <p><img src="https://i.stack.imgur.com/gJu4w.png" alt="enter image description here"></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload