Skip to content

Instantly share code, notes, and snippets.

@jeffora
Created September 27, 2011 01:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeffora/1243959 to your computer and use it in GitHub Desktop.
Save jeffora/1243959 to your computer and use it in GitHub Desktop.
Massive dynamic issues
// Example 1:
// conn has a compile time type of DbConnection, as this is what is returned by OpenConnection
// cmd has compile time type of DbCommand, as this is what is returned by CreateCommand
// Both have runtime types of the more specific SqlConnection/SqlCommand
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;
}
// Example 2:
// conn has a compile time type of DbConnection, as this is what is returned by OpenConnection
// cmd is only evaluated at runtime due to dynamic. At runtime, it becomes the most specific SqlCommand
// SqlCommand.Connection requires SqlConnection and although conn's runtime type is SqlConnection, its
// compile-time is still DbConnection and thus you get the error
public static dynamic DynamicWeirdness() {
dynamic ex = new ExpandoObject();
ex.TableName = "Products";
using (var conn = OpenConnection()) {
var cmd = CreateCommand(ex);
cmd.Connection = conn;
}
Console.WriteLine("It worked!");
Console.Read();
return null;
}
// Example 3:
// conn has a compile time type of DbConnection, as this is what is returned by OpenConnection
// cmd is evaluated at runtime due to dynamic to be any type compatible with DbCommand.
// Runtime type is still SqlCommand, but compile-time is specified as DbCommand (due to not using var).
// DbCommand.Connection accepts DbConnection, which is the compile-time type of conn
public static dynamic DynamicWeirdness() {
dynamic ex = new ExpandoObject ();
ex.Query = "SELECT * FROM Products";
using (var conn = OpenConnection()) {
DbCommand cmd = CreateCommand(ex); // <-- DON'T USE VAR
cmd.Connection = conn;
}
Console.WriteLine("It worked!");
Console.Read();
return null;
}
@robconery
Copy link

I don't think this is the case. The reasoning is that the entire block is a dynamic expression - given that then there is no compile time type. This has nothing to do with DbCommand/SqlCommand - if I cast "ex" as ExpandoObject it still works regardless of what the compiler things the Command is.

@jeffora
Copy link
Author

jeffora commented Sep 27, 2011

I disagree. I assume by 'the entire block is a dynamic expression' you mean the fact that the method returns dynamic? This has nothing to do with compile time types within the method, where applicable. Furthermore, the behaviour remains when you change the method to return object or make it a void method. Casting to ExpandoObject works for the same reason that removing var and using DbCommand works - it changes the compile-time type to DbCommand. If you use the dynamic object as parameter, hover over the var keyword in VS, the tooltip says its type is dynamic. Cast ex to ExpandoObject and hover again, it now has a compile-time type of DbCommand.

@robconery
Copy link

OK so the next twist is that if I set "using dynamic conn = OpenConnection()" it works as well. What I mean by "the entire block is an expression" means exactly that - if you hover over it the compiler has no idea what's going on - there's "too much dynamic" happening. So it hands it off to the runtime binder to figure out.

Now here's where it gets interesting. Take a look at the question again - see the last edit? See where I output the runtime types for each variable? They're SqlClient.

We're talking in circles here - but everything you're writing here is not convincing me that there's a compile-time type for the code I've written. There can't be. It's dynamic and maybe IL is taking a swing at figuring it out... but there's no way that you and I can know what that special magic is since we're not compilers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment