Why does Expression.TryFault() always fail to Expression.Lambda<>().Compile() in netfx? - c#

Given the following code:
using System;
using System.Linq.Expressions;
Console.WriteLine(Expression.Lambda<Func<string>>(Expression.TryFault(Expression.Constant("hi"), Expression.Constant("alternative"))).Compile()());
I am targeting net462 (repro project here).
Unhandled Exception: System.NotSupportedException: The requested operation is invalid for DynamicMethod.
at System.Reflection.Emit.DynamicILGenerator.BeginFaultBlock()
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitTryExpression(Expression expr)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.EmitLambdaBody(CompilerScope parent, Boolean inlined, CompilationFlags flags)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator)
at System.Linq.Expressions.Expression`1.Compile()
at Program.<Main>$(String[] args)
Why isn’t this emission supported?
I know that my example here is not a good example of when one would want to use Expression.TryFault(). However, the semantics fit exactly what I want in a certain scenario (running some code only if an exception is thrown by a particular expression without actually catching the original exception (I am actually trying to generate a more specific exception by rerunning parts of the original expression in a bunch of try/catch with the idea that the exception case will be exceptional and rarely run)).
Why does netfx throw here? I thought that even though C# doesn’t support fault blocks, netfx did. What is DynamicMethod and why is it special? Is there any suggestion for a way to express these semantics without encountering this error?

Related

Getting expression values breaks when class is in other projects

I've written some code that takes an Expression and acts as a proxy to make certain calls. The main bit of code that makes this work is such
private static IEnumerable<object> GetArguments(MethodCallExpression body)
{
IEnumerable<object> arguments =
body.Arguments.Select(
expression =>
{
MemberExpression member = expression as MemberExpression;
return ((dynamic) member.Member).GetValue(((ConstantExpression) member.Expression).Value);
});
return arguments;
}
This gets the values of the parameters present in the Expression and returns them in an IEnumerable. That's the behavior I get when I wrote this in the initially consuming project and I can see the resulting argument values being output correctly. I even moved this to a test bed project to test the code and it worked fine there as well. However, when I put the .cs files in another project, updating the namespaces, and reference it to be able to use it widely, I get exceptions such as
System.InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Linq.Expressions.ConstantExpression'.
and I can't even use my application.
I've rolled my extraction back to the "it works locally" state to ensure it, in fact, worked, and it did. However, I have noticed I still get some exceptions in my logging even though it didn't throw up on me like it does when it's external to the project. I can still use my application in spite of this.
Repeating the move to an external project and using it by way of a reference reintroduces those errors and I can't even use my app.
New question: how do I handle PropertyExpressions? They don't expose a Value property and are internal so I there's no cast and check. MemberExpression also doesn't have a Value property.
The simplest solution would be not to rely on the shape of the expressions at all and let the Expression Tree library evaluate each subexpression for you by building a LambdaExpression and then using Compile() on it and executing the returned delegate:
private static IEnumerable<object> GetArguments(MethodCallExpression body)
{
return body.Arguments.Select(
expression => Expression.Lambda<Func<object>>(
Expression.Convert(expression, typeof(object))).Compile()());
}
Note that compiling each subexpression will take some time, so this approach is going to be relatively slow.
You should evaluate the expression and not rely on it's shape. The easiest way is to call .Compile().Invoke(), but that is slow and creates a memory-leak. You can avoid that by interpreting the expression (stepping recursively through it with a visitor and perform the operations in it manually) or cache your compilation result. I wrote a library that can do both, is fast and used in production for quite some time now: https://github.com/Miaplaza/expression-utils

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

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.

How to Remove Code Analysis Warning CA1006? [duplicate]

I have a function used when calling a service. Before it call the service, it will create a log entry:
protected TResult CallService<TService, TResult>(TService service,
Expression<Func<TService, TResult>> functionSelector)
{
Logger.LogServiceCall(service, functionSelector);
return functionSelector.Compile()(service);
}
The Visual Studio 2010 Code Analyzer informs me that I shouldn't use Nested Type in the following message:
CA1006 : Microsoft.Design : Consider a
design where
'ServiceManager.CallService<TService,
Result>(TService,
Expression<Func<TService, TResult>>)'
doesn't nest generic type
'Expression<Func<TService, TResult>>'.
While I could simply create a suppression rule for this entry, is there is an alternative that exist that would prevent displaying such warning?
I would suppress it in this case, with the reason that the caller doesn't have to cope with nested generics, he is just passing a lambda expression, which is easy to use.
CA does not make exceptions for lambda expressions. Sometimes It is better to suppress it then to write weird code.
I'll be honest, I suppress that rule most of the time. While I can understand that some of the construction of the nested types can be avoided, it is more often than not the case; you usually want to leave that to the call site because you can't guarantee that the call site will want the nested generic type to be instantiated in the same way.
This is one of those rules that I find a bit overbearing; I generally agree with most of them, but not this one.
Methods like yours are used extensively in Linq, for example:
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate)
The alternative would be to declare a delegate type to replace the nested Func<TService, TResult>, but that's just as likely to confuse a more experienced developer who's used to working with expression trees.
Microsoft obviously makes an exception to CA1006 for nested generic expression types, and so should we.
You can suppress the message warning with SuppressMessageAttribute.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design","CA1006:<rule name>")]
protected TResult CallService<...Snip...

What exception to throw when parsing a byte array? (C#)

I'm parsing a byte array, which is in effect a fix length record that is being sent on a message bus. If the data isn't valid (garbled or doesn't fit the spec for the record) then I want to throw an exception. Something like this:
public DomainObject ParseTheMessage(byte[] payload){
Validate(payload);//throws an exception if invalid
...do creation of domain object
}
Does anyone know if there is a good standard exception I can throw in these circumstances or should I just create my own specific exception?
You can just use ArgumentException:
throw new ArgumentException("payload", "'payload' should be...");
As mentioned below by x0r, MSDN recommends only deriving from ArgumentException, doing so may or may not give you any added value, this depends on what defines an 'invalid' argument passed through the parameter - if you can define strict rules of what can go wrong, then you may well benefit from creating more precisely named exceptions that derive from ArgumentException.
Or, you could use InvalidDataException with the same kind of informative message, if you have one:
The exception that is thrown when a data stream is in an invalid format.
Although referring to a data stream, there might be some objections - let's see.
If it is simply for a general 'bad format' exception, then you do have FormatException - but that might be faaar too general for your circumstance (see above), though maybe a far better exception to derive from, it really does depend:
The exception that is thrown when the format of an argument does not meet the parameter specifications of the invoked method.
You may throw an ArgumentException with a custom InnerException.
If data validity criterion is application-specific and doesn't match any general case (like index out of range etc.), I think it is better to use your own exception. For standard case use existing exception, for example, NullPointerException if payload == null.
System.ArgumentOutOfRangeException:
ArgumentOutOfRangeException is thrown when a method is invoked and at
least one of the arguments passed to the method is not null and does
not contain a valid value.
throw new ArgumentOutOfRangeException("payload","description of the specific problem");

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