I was using Dapper and having it return a dynamic IEnumerable, like this:
var rows = conn.Query("SELECT * FROM T WHERE ID = #id", new { id = tableId });
var row = rows.FirstOrDefault();
Here, rows is of type IEnumerable<dynamic>. The IntelliSense says FirstOrDefault() is awaitable, and has the usage await FirstOrDefault(). Not all LINQ queries are shown as awaitable, but it seems like especially those that somehow single out elements are.
As soon as I instead use strong typing, this behavior goes away.
Is it because .NET can't know if the type you are receiving at runtime is awaitable or not, so that it "allows" it, in case you need it? But doesn't enforce it? Or am I supposed to, due to some Dynamic Language Runtime behavior, actually use await here?
I have kept searching but not found the smallest thing about this online.
async-await feature of compiler depends on Duck Typing. So everything that has method GetAwaiter (either instance or extension method) which returns type that implements INotifyCompletion interface and has the next fields:
bool IsCompleted { get; }
void|TResult GetResult()
can be awaited.
You can call whatever you want on dynamic type at compile time (from docs):
At compile time, an element that is typed as dynamic is assumed to support any operation.
That is why compiler does not show any warnings/errors at compile time, but at runtime you will get an exception similar to the following:
RuntimeBinderException.
'<>f__AnonymousType0' does not contain a definition for 'GetAwaiter'
If you specify type explicitly compiler will search for method GetAwaiter. Then if your strong type does not contain it you will get compile time error.
So, the answer to your question is that indeed that's because of special behavior of dynamic.
Related
While reading Jon Skeet's book C# In Depth 4th Edition, I was doing some tests on dynamic binding limitations related to extension methods.
As Jon says in that chapter, dynamic binding is not supported for extension methods in .NET, so the compiler prevents us from passing a dynamic value as an argument by raising the appropriate error CS1973. So for the following code:
//Provided this extension method
public static int GetFoo(this List<int> target, int value) => value * 10;
//And the following code at the call site
dynamic d = 1;
var items = new List<int> { 1, 2, 3 };
var result = items.GetFoo(d); //Error CS1973 as expected because
//we passed a dynamic argument
The error message is straightforward:
List<int> has no applicable method named GetFoo but appears to have an extension method by that name. Extension methods cannot be
dynamically dispatched. Consider casting the dynamic arguments or
calling the extension method without the extension method syntax.
No surprise until now. But if we change slightly the extension method to make it generic in order to accept a List<T> instead of List<int>, the compiler raises now a different error CS1929.
//The generic version of 'GetFoo' seen above
public static int GetFooGeneric<T>(this List<T> target, int value) => value * 10;
//Unexpectedly, the following call raises error CS1929 (instead of CS1973)
var result = items.GetFooGeneric(d);
And the error message is, in my opinion, as misleading as senseless:
List<int> does not contain a definition for GetFooGeneric and the best
extension method overload Extensions.GetFooGeneric<T>(List<T>, int) requires a receiver of type List<T>.
Misleading because it hides the non-support of dynamic binding for extension methods, and it doesn't make sense to have an instance of type List<T> as the receiver to call the extension method on.
Does anyone know what's happening behind the scenes that makes the compiler raise this misleading error message?
PS: As a side note, if we supply the type argument for that same generic method, the compiler then raises the appropriate error CS1973 again as expected.
//By helping the compiler explicitly, it raises CS1973 appropriately
var result = items.GetFooGeneric<int>(d);
Ouch. That's really bad! I don't recall if that one was my fault or not, but you are definitely right that this is a terrible error message.
It possibly is a result of some heuristics we put into the analyzer to deal with situations where you are actually typing the code in the editor and we need to do type inference on an incomplete or wrong call to an extension method in order to get the IntelliSense right; perhaps that is interacting badly with the dynamic argument? But I would need to actually look at the code to refresh my memory there.
If I have time later today I'll look at the Roslyn sources and see if I recognize this code path.
I know that is not much of an answer to your question, but I haven't debugged through that code path since at least 2012 so my recall of those design choices is not what it once was. :)
You write: GetValueGeneric<T>(this List<T> target, int value) Note that you write Value
Calling items.GetFooGeneric(d); will result in CS1929 because your function does not exist.
I tryied items.GetValueGeneric(d); and it gives CS1973
I am having problem while using AsQueryable, I found some example in which casting i.e. AsQueryable required for this extension and in some example directly as AsQueryable(). I check both case with Stopwatch and concluded with almost same result for multiple investigation.
Lets take example:
//With AsQueryable()
var studentId = dbContext.Students.AsQueryable().Where(a=>a.Name == "Abc").Select(a=>a.Id).FirstOrDefault();
//With AsQueryable<Student>()
var studentId = dbContext.Students.AsQueryable<Student>().Where(a=>a.Name == "Abc").Select(a=>a.Id).FirstOrDefault();
What is difference between using AsQueryable() and AsQueryable<type>() and which is efficient?
When you call AsQueryable() without specifying generic parameter type it's inferred by compiler from an object you call it at.
var source = new List<int>();
var queryable = source.AsQueryable(); // returns IQueryable<int>
is equivalent to
var queryable = source.AsQueryable<int>();
Update
To answer question asked in comments:
Then what is the use for having two different way? Is there any particular situation when we have to use only one of it?
Yes, you can't specify type parameter explicitly when using anonymous types, because you don't have class name:
source.Select((x,i) => new { Value = x, Index = i }).AsQueryable();
And that's exactly why type inference was introduced: to let you call generic methods without specifying type parameters when using anonymous types. But because it works not only with anonymous types, and saves you unnecessary typing, it's very common to rely on type inference whenever it's possible. That's why you'll probably see AsQueryable() without type parameter most of the times.
Whenever possible, the compiler can do type inference for you:
http://msdn.microsoft.com/en-us/library/twcad0zb.aspx
And in that case, there's no difference, advantage, or penalty either way. Type inference just makes your life easier and your code shorter.
However, I've run into cases when consuming APIs where a type implements several interfaces, e.g.
IEnumerable<IMySimpleThing>, IEnumerable<IMyComplexThing>, IEnumerable<MyComplexThing>
and type inference isn't sufficient if you're trying to get at a specific interface, e.g.
IEnumerable<MyComplexThing>
So in that case, specifying type to the generic, like .AsQueryable<MyComplexThing>(), will do the trick.
In The C# Programming language Bill Wagner says:
Many people confuse dynamic binding with type inference. Type
inference is statically bound. The compiler determines the type at
compile time. For example:
var i = 5; //i is an int (Compiler performs type inference)
Console.WriteLine(i); //Static binding to Console.WriteLine(int)
The compiler infers that i is an integer. All binding on the variable
i uses static binding.
Now, given this information and my own made-up dynamic scenerio:
dynamic i = 5; //Compiler punts
Console.WriteLine(i);//This is now dynamically bound
We know type inference is statically bound. This implies that there is no way a dynamic variable can use type inference to determine a type. How does a dynamic type get resolved without using type inference?
Update
To try and clarify...at runtime we must somehow figure out what type i is right? Because I assign a literal 5 then the runtime can infer that i is an int. Isn't that type inference rather than dynamic binding?
What distinction is Bill making?
The distinction that Bill is making is that many people think that:
var x = Whatever();
x.Foo();
will work out at runtime what method Foo to call based on the type of object returned at runtime by Whatever. That's not true; that would be
dynamic x = Whatever();
x.Foo();
The var just means "work out the type at compile time and substitute it in", not "work it out at runtime".
So if I have
dynamic i = 5;
Console.WriteLine(i);
What happens?
The compiler generates code that is morally like this:
object i = (object)5;
DynamicCallSite callSite = new DynamicCallSite(typeof(Console), "WriteLine"));
callSite.Invoke(i);
It is a bit more complicated than that; the call site is cached, for one thing. But this gives you the flavour of it.
The invocation method asks i for its type via GetType and then starts up a special version of the C# compiler that can understand reflection objects. It does overload resolution on the members of Console named WriteLine, and determines which overload of Console.WriteLine would have been called had i been typed as int in the first place.
It then generates an expression tree representing that call, compiles the expression tree into a delegate, caches it in the call site, and invokes the delegate.
The second time you do this, the cached call site looks in its cache and sees that the last time that i was int, a particular delegate was invoked. So the second time it skips creating the call site and doing overload resolution, and just invokes the delegate.
For more information, see:
http://ericlippert.com/2012/10/22/a-method-group-of-one/
http://ericlippert.com/2012/11/05/dynamic-contagion-part-one/
http://ericlippert.com/2012/11/09/dynamic-contagion-part-two/
A historical perspective on the feature can be obtained from Chris and Sam's blogs:
http://blogs.msdn.com/b/cburrows/archive/tags/dynamic/
http://blogs.msdn.com/b/samng/archive/tags/dynamic/
They did a lot of the implementation; however some of these article reflect outdated design choices. We never did go with "The Phantom Method" algorithm, regrettably. (Not a great algorithm, but a great name!)
I am attempting to process results from a select (Find.., All, etc) from simple.data, but I am getting errors:
var db = Database.Open();
var codes = db.Code.All();
// 'object' does not contain a definition for 'First'
var firstcode = codes.First();
// 'object' does not contain a definition for 'ToList'
List<Code> codeList = codes.ToList();
The type of codes is {System.Linq.Enumerable.WhereSelectListIterator<System.Collections.Generic.IDictionary<string,object>,Simple.Data.DynamicRecord>}.
What am I missing? Someone add a simple.data tag please.. :)
The main reason that LINQ methods don't work on the object returned from db.Code.All() is that at that point in the code, the C# compiler doesn't know that it's an IEnumerable, so it can't hook up the extension methods. Of course, the C# compiler doesn't know what the object is, because it's dynamic, so it passes over it and assumes that the First() method will be resolved at runtime.
I've tried to address this in more recent releases, and many methods are supported, including ToList, First, FirstOrDefault, Single, SingleOrDefault and some others. Still more are to come soon (within the 0.9.x releases).
The easiest way to bring the compiler back into full effect is to explicitly specify the type instead of using var. For example
IEnumerable<Code> codes = db.Codes.All();
will cause an "implicit cast" (quoted because it's not really, but it acts like one) from the SimpleQuery type to the IEnumerable type, at which point you can start using LINQ methods on it again.
Doh, simple answer. I was using the latest version from https://github.com/markrendle/Simple.Data/downloads but in fact it should installed from nuget http://nuget.org/List/Packages/Simple.Data.Core.. :(
It looks like you need a using System.Linq; declaration.
If the actual error message contains the word 'object' then it indicates that the type of codes returned from your call is an object, not a System.Linq.Enumerable.WhereSelectListIterator<System.Collections.Generic.IDictionary<string,object>,Simple.Data.DynamicRecord>} as you say, which would be the cause of the error.
So odd situation that I ran into today with OrderBy:
Func<SomeClass, int> orderByNumber =
currentClass =>
currentClass.SomeNumber;
Then:
someCollection.OrderBy(orderByNumber);
This is fine, but I was going to create a method instead because it might be usable somewhere else other than an orderBy.
private int ReturnNumber(SomeClass currentClass)
{
return currentClass.SomeNumber;
}
Now when I try to plug that into the OrderBy:
someCollection.OrderBy(ReturnNumber);
It can't infer the type like it can if I use a Func. Seems like to me they should be the same since the method itself is "strongly typed" like the Func.
Side Note: I realize I can do this:
Func<SomeClass, int> orderByNumber = ReturnNumber;
This could also be related to "return-type type inference" not working on Method Groups.
Essentially, in cases (like Where's predicate) where the generic parameters are only in input positions, method group conversion works fine. But in cases where the generic parameter is a return type (like Select or OrderBy projections), the compiler won't infer the appropriate delegate conversion.
ReturnNumber is not a method - instead, it represents a method group containing all methods with the name ReturnNumber but with potentially different arity-and-type signatures. There are some technical issues with figuring out which method in that method group you actually want in a very generic and works-every-time way. Obviously, the compiler could figure it out some, even most, of the time, but a decision was made that putting an algorithm into the compiler which would work only half the time was a bad idea.
The following works, however:
someCollection.OrderBy(new Func<SomeClass, int>(ReturnNumber))