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...
Related
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
Understanding the C# Language Specification on overload resolution is clearly hard, and now I am wondering why this simple case fails:
void Method(Func<string> f)
{
}
void Method(Func<object> f)
{
}
void Call()
{
Method(() => { throw new NotSupportedException(); });
}
This gives compile-time error CS0121, The call is ambiguous between the following methods or properties: followed by my two Method function members (overloads).
What I would have expected was that Func<string> was a better conversion target than Func<object>, and then the first overload should be used.
Since .NET 4 and C# 4 (2010), the generic delegate type Func<out TResult> has been covariant in TResult, and for that reason an implicit conversion exists from Func<string> to Func<object> while clearly no implicit conversion can exist from Func<object> to Func<string>. So it would make Func<string> the better conversion target, and the overload resolution should pick the first overload?
My question is simply: What part of the C# Spec am I missing here?
Addition: This works fine:
void Call()
{
Method(null); // OK!
}
My question is simply: What part of the C# Spec am I missing here?
Summary:
You have found a minor known bug in the implementation.
The bug will be preserved for backwards compatibility reasons.
The C# 3 specification contained an error regarding how the "null" case was to be handled; it was fixed in the C# 4 specification.
You can reproduce the buggy behavior with any lambda where the return type cannot be inferred. For example: Method(() => null);
Details:
The C# 5 specification says that the betterness rule is:
If the expression has a type then choose the better conversion from that type to the candidate parameter types.
If the expression does not have a type and is not a lambda, choose the conversion to the type that is better.
If the expression is a lambda then first consider which parameter type is better; if neither is better and the delegate types have identical parameter lists then consider the relationship between the inferred return type of the lambda and the return types of the delegates.
So the intended behaviour is: first the compiler should check to see if one parameter type is clearly better than the other, regardless of whether the argument has a type. If that doesn't resolve the situation and the argument is a lambda, then check to see which of the inferred return type converted to the parameters' delegate types' return type is better.
The bug in the implementation is the implementation doesn't do that. Rather, in the case where the argument is a lambda it skips the type betterness check entirely and goes straight to the inferred return type betterness check, which then fails because there is no inferred return type.
My intention was to fix this for Roslyn. However, when I went to implement this, we discovered that making the fix caused some real-world code to stop compiling. (I do not recall what the real-world code was and I no longer have access to the database that holds the compatibility issues.) We therefore decided to maintain the existing small bug.
I note that the bug was basically impossible before I added delegate variance in C# 4; in C# 3 it was impossible for two different delegate types to be more or less specific, so the only rule that could apply was the lambda rule. Since there was no test in C# 3 that would reveal the bug, it was easy to write. My bad, sorry.
I note also that when you start throwing expression tree types into the mix, the analysis gets even more complicated. Even though Func<string> is better than Func<object>, Expression<Func<string>> is not convertible to Expression<Func<object>>! It would be nice if the algorithm for betterness was agnostic with respect to whether the lambda was going to an expression tree or a delegate, but it is in some ways not. Those cases get complicated and I don't want to labour the point here.
This minor bug is an object lesson in the importance of implementing what the spec actually says and not what you think it says. Had I been more careful in C# 3 to ensure that the code matched the spec then the code would have failed on the "null" case and it would then have been clear earlier that the C# 3 spec was wrong. And the implementation does the lambda check before the type check, which was a time bomb waiting to go off when C# 4 rolled around and suddenly that became incorrect code. The type check should have been done first regardless.
Well, you are right. What causes problem here is the delegate you are passing as an argument. It has no explicit return type, you are just throwing an exception. Exception is basically an object but it is not considered as a return type of a method. Since there is no return call following the exception throw, compiler is not sure what overload it should use.
Just try this
void Call()
{
Method(() =>
{
throw new NotSupportedException();
return "";
});
}
No problem with choosing an overload now because of explicitly stated type of an object passed to a return call. It does not matter that the return call is unreachable due to the exception throw, but now the compiler knows what overload it should use.
EDIT:
As for the case with passing null, frenkly, I don't know the answer.
LINQPad example:
void Main()
{
One(i => PrintInteger(i));
One(PrintInteger);
Two(i => PrintInteger(i));
// Two(PrintInteger); - won't compile
}
static void One(Action<int> a)
{
a(1);
}
static void Two(Expression<Action<int>> e)
{
e.Compile()(2);
}
static void PrintInteger(int i)
{
Console.WriteLine(i);
}
Uncommenting the Two(PrintInteger); line results in an error:
cannot convert from 'method group' to
'System.Linq.Expressions.Expression<System.Action<int>>'
This is similar to Convert Method Group to Expression, but I'm interested in the "why." I understand that Features cost money, time and effort; I'm wondering if there's a more interesting explanation.
Because, in order to get the expression tree, we need a representation of the method in (uncompiled) source form. Lambda expressions are locally available in the source code and therefore are always available uncompiled. But methods may not be from inside the current assembly, and may thus be available only in compiled form.
Granted, the C# compiler could decompile the assembly’s IL code to retrieve an expression tree but as you mentioned, implementing feature costs money, this particular feature isn’t trivial, and the benefits are unclear.
There is no reason in principle. It could be done this way. The compiler could just create the lambda by itself before converting it (this is obviously always possible - it knows the exact method being called so it can just create a lambda from its parameters).
There is one catch, though. The name of the parameter of your lambda is normally hard-coded into the IL being generated. If there is no lambda, there is no name. But the compiler could either create a dummy name or reuse the names of the method being called (they are always available in the .NET assembly format).
Why didn't the C# team decide to enable this? The only reason that comes to mind is that they wanted to spend their time elsewhere. I applaud them for that decision. I'd rather have LINQ or async than this obscure feature.
In the One example, you are implicitly creating an Action<int> delegate. It's the same as:
One( new Action<int>( PrintInteger ) );
I believe this is in the language to improve the syntax for subscribing to events.
The same thing doesn't happen for Expression<T>, which is why your second example doesn't compile.
EDIT :
It's called a "method group conversion". It's in the C# spec - section 6.6
An implicit conversion (§6.1) exists from a method group (§7.1) to a compatible delegate type
Say I have a function such as:
public TProperty Foo<TClass, TProperty>(TClass instance, Expression<Func<TClass, TProperty>> expression)
{
...
}
But then I realize it should only be used for value types, so I add a constraint
public TProperty Foo<TClass, TProperty>(TClass instance, Expression<Func<TClass, TProperty>> expression)
where TProperty : struct
{
...
}
But I then discover that this won't let me pass in expressions that take a nullable TProperty. The only way I can see to handle this is to do the following:
public TProperty Foo<TClass, TProperty>(TClass instance, Expression<Func<TClass, TProperty?>> expression)
where TProperty : struct
{
...
}
But now I am forced to maintain two methods that do exactly the same thing, except that one deals with nullables, and one doesn't.
Further more I can't extract them into a common method, because even though a conversion exists from T to T?, there is apparently no conversion from
Expression<Func<T1, T2>>
to
Expression<Func<T1, T2?>>
If the body of these methods is complicated, I really don't want to have to maintain two separate versions of them, especially when in fact it is a whole family of functions.
Is there any way to avoid this code duplication and still have the compiler enforce that the expression must end in either a value type or a nullable?
(I am currently using C# 3.5, but am open to more recent versions if they provide a clean solution.)
Depending on what you're doing with the expression, you could make both overloads call a private overlaod that takes a (untyped) LambdaExpression.
In cases like these it can be still OK to use method overloading provided the logic is refactored to a private method.
I think you can restrict it on where TProperty : Nullable<TProperty> though I have not checked this
In .NET 4, Func<P, Q> is actually covariant on Q. So this idea might work, but alas, Nullable<T> is not related to T. (Here is an example.), so Func<P, Q> has no chance to be used where Func<P, Q?> is expected.
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...