Exception (sometimes) is thrown when awaiting a method with dynamic argument - c#

I have the following code:
string commandText = await _client
.GetCommandTextAsync("Products", x.ProductName == "Chai");
The second parameter (x.ProductName == "Chai") contains a dynamic clause (x.ProductName), so the resulting expression is also dynamic. When this code is executed on .NET 4.0, sometimes it throws the following exception:
System.InvalidCastException Unable to cast object of type
'System.Runtime.CompilerServices.TaskAwaiter`1[System.String]' to type
'System.Runtime.CompilerServices.INotifyCompletion'.
The exception is not thrown if I explicitly case the method result to Task:
string commandText = await (Task<string>)_client
.GetCommandTextAsync("Products", x.ProductName == "Chai");
Is there a more elegant way to resolve this problem (without casting every single line of code that awaits for a dynamic result), or is this a known problem with using TPL on .NET 4.0.
I haven't experienced this on .NET 4.5.

Here is a theory:
According to the TaskAwaiter definition:
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
public struct TaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion
it seems that TaskAwaiter is an INotifyCompletion. You said you have dynamic clause in your code. As MS states dynamic objects are mostly behaves like object. Thus casting is required in the code which is handled by run-time or compiler.
You also stated that platform is Xamarin iOS. Which possibly utilizing HostProtectionAttribute for example to block usage of some classes or etc.
The TaskAwaiter implementation is marked with SecurityAction.LinkDemand and again if we check MSDN it says:
...
LinkDemand (do not use in the .NET Framework 4)
...
So conclusion is: The platform which code is running, is lacking security implementations required by Host Protection and methods are not invoked (while security is not working properly) Casting is one of "secure" operation thus this type of runtime casting fails.
if you explicitly cast like you did, there is no problem because compiler does not add the "buggy" code.

Related

C# compiler fails with misleading error when calling generic extension method with a dynamic argument

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

Marshalling Microsoft.VisualBasic.Collection to COM

I have a C# class that has a property(name is List) of type Microsoft.VisualBasic.Collection. We need to exposed this property to COM. For that, I was writing an interface for my class such that the property would marshaled as of UnmanagedType.IDispatch.
Something like this:
[DispId(0x68030000)]
Collection List { [DispId(0x68030000)] [return: MarshalAs(UnmanagedType.IDispatch)] get; }
This piece of code was earlier in VB and was being used by C++ as tye VT_DISPATCH. However, while building the C# library, I get the following error:
C:\Program Files
(x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(4335,5):
error MSB3212: The assembly "Name.dll" could not be converted to a
type library. Type library exporter encountered an error while
processing 'Namespace.InterfaceName.get_List(#0), ProjectName'. Error:
Error loading type library/DLL.
I read through few of the posts online which suggested that such errors might cause because of repetitive GUIDs. But that is not the case. I tried with multiple GUIDs. I don't feel this is an issue with any other attribute that I had set on my Interface since, I am able to marshal other properties and function calls ( some of them use primitive types and others use custom classes) successfully.
This is how it is consumed in the consuming C++ application:
LPDISPATCH result;
InvokeHelper(0x68030000, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result, NULL);
return result;
This has become a go live issue with the client and I really do not have much time to continue investigation since this is due tomorrow.
Appreciate any help!
I don't think Microsoft.VisualBasic.Collection is COM-visible. Therefore, you cannot use this type as a return value or parameter in a COM class or interface. However, ICollection (which Microsoft.VisualBasic.Collection implements) is COM visible. If that would suit your purposes, use that as the type of your property rather than Microsoft.VisualBasic.Collection.

Why is First() or ElementAt() on a dynamic IEnumerable awaitable?

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.

How do I tell in c# codecontracts that a external method never returns null?

I have the following piece of c# code:
myClaimsIdentity.FindFirst(ClaimTypes.NameIdentifier).Value;
CodeContract knows that myClaimsIdentity is never null. But it complains that the FindFirst(string) method might return null:
Warning CodeContracts: Possibly calling a method on a null reference. Do you expect that System.Security.Claims.ClaimsIdentity.FindFirst(System.String) returns non-null?
I do expect this, but how can I tell it to the CodeChecker? Of course I can't change the the FindFirst(string) since it comes from an external library.
The simple approach is:
var nameIdentifier = myClaimsIdentity.FindFirst(ClaimTypes.NameIdentifier);
Contract.Assume(nameIdentifier != null);
nameIdentifier.Value;
Code contracts will not try to prove the Assume condition, but will use it when proving other requirements.
It's probably possible to create a contract reference assembly for the external code which has the appropriate Ensures post-conditions. The code contracts team does this for the BCL types. But I don't know how to do that.

Why calling ISet<dynamic>.Contains() compiles, but throws an exception at runtime?

Please, help me to explain the following behavior:
dynamic d = 1;
ISet<dynamic> s = new HashSet<dynamic>();
s.Contains(d);
The code compiles with no errors/warnings, but at the last line I get the following exception:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.Collections.Generic.ISet<object>' does not contain a definition for 'Contains'
at CallSite.Target(Closure , CallSite , ISet`1 , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
at FormulaToSimulation.Program.Main(String[] args) in
As far as I can tell, this is related to dynamic overload resolution, but the strange things are
(1) If the type of s is HashSet<dynamic>, no exception occurs.
(2) If I use a non-generic interface with a method accepting a dynamic argument, no exception occurs.
Thus, it looks like this problem is related particularly with generic interfaces, but I could not find out what exactly causes the problem.
Is it a bug in the compiler/typesystem, or legitimate behavior?
The answers you have received so far do not explain the behaviour you are seeing. The DLR should find the method ICollection<object>.Contains(object) and call it with the boxed integer as a parameter, even if the static type of the variable is ISet<dynamic> instead of ICollection<dynamic> (because the former derives from the latter).
Therefore, I believe this is a bug and I have reported it to Microsoft Connect. If it turns out that the behaviour is somehow desirable, they will post a comment to that effect there.
Why it compiles: the entire expression is evaluated as dynamic (hover your mouse over it inside your IDE to confirm), which means that it is a runtime check.
Why it bombs: My (completely wrong, see below) guess is that it is because you cannot implement a dynamic interface in such a manner. For example, the compiler does not allow you to create a class that implements ISet<dynamic>, IEnumerable<dynamic>, IList<dynamic>, etc. You get a compile-time error stating "cannot implement a dynamic interface". See Chris Burrows' blog post on this subject.
http://blogs.msdn.com/b/cburrows/archive/2009/02/04/c-dynamic-part-vii.aspx
However, since it's hitting the DLR anyway, you can make s completely dynamic.
dynamic s = new HashSet<dynamic>;
s.Contains(d);
Compiles and runs.
Edit: the second part of this answer is completely wrong. Well, it is correct in that you can't implement such an interface as ISet<dynamic>, but that's not why this blows up.
See Julian's answer below. You can get the following code to compile and run:
ICollection<dynamic> s = new HashSet<dynamic>();
s.Contains(d);
The Contains method is defined on ICollection<T>, not ISet<T>. The CLR doesn't allow an interface base method to be called from a derived interface. You usually doesn't see this with static resolution because the C# compiler is smart enough to emit a call to ICollection<T>.Contains, not the non-existing ISet<T>.Contains.
Edit: The DLR mimics the CLR behavior, that's why you get the exception. Your dynamic call is done on an ISet<T>, not an HashSet<T> the DLR will mimics the CLR: for an interface, only interfaces methods are searched for, not base interfaces (contrary to classes where this behavior is present).
For an in-depth explanation, see a previous response of mine to a similar question:
Strange behaviour when using dynamic types as method parameters
Note that the type dynamic doesn’t actually exist at run-time. Variables of that type are actually compiled into variables of type object, but the compiler turns all the method calls (and properties and everything) that involve such an object (either as the this object or as a parameter) into a call that is resolved dynamically at runtime (using System.Runtime.CompilerServices.CallSiteBinder and related magic).
So what happens in your case is that the compiler:
turns ISet<dynamic> into ISet<object>;
turns HashSet<dynamic> into HashSet<object>, which becomes the actual run-time type of the instance you’re storing in s.
Now if you try to invoke, say,
s.Contains(1);
this actually succeeds without a dynamic invocation: it really just calls ISet<object>.Contains(object) on the boxed integer 1.
But if you try to invoke
s.Contains(d);
where d is dynamic, then the compiler turns the statement into one that determines, at runtime, the correct overload of Contains to call based on the runtime type of d. Perhaps now you can see the problem:
The compiler emits code that definitely searches the type ISet<object>.
That code determines that the dynamic variable has type int at runtime and tries to find a method Contains(int).
ISet<object> does not contain a method Contains(int), hence the exception.
ISet interface does not have a method 'Contains', HashSet does however?
EDIT
What i meant to say was the binder resolves 'Contains' when given the HashSet concreate type, but doesnt find the inherited 'Contains' method in the interface...

Categories