Why can you not use anon function with a dynamic parameter? - c#

Just ran into this today
An anonymous function or method group cannot be used as a constituent
value of a dynamically bound operation.
when trying to do
static R ifNotNull<R>(dynamic o, Func<dynamic, R> returnFunc, R otherwise) {
return ReferenceEquals(null, o) ? otherwise : returnFunc(o);
}
and use it with
dynamic firstAddress = ...;
return ifNotNull<string>(firstAddress, (a) => a.address_1, null)
Now most of the limitations on dynamics make sense to me - you can't use an extension method because how is the compiler supposed to decide which static to compile it to? But I don't get this here. Where does the confusion come in? What exactly is the limitation?

What is the static type of the lamba a => a.address_1? You may be tempted to say it's a Func<dynamic, dynamic>. But remember:
A lambda expression is an anonymous function that you can use to
create delegates or expression tree types.
So maybe it's an Expression<Func<dynamic, dynamic>>. A lamda by itself doesn't have a single static type.
Now normally type inference would figure out that you're passing the lamba to a function that takes a Func and it will be converted to a delegate at compile time. However when you are calling with dynamic arguments the method call is dispatched dynamically.
If you have a method call with a dynamic argument, it is dispatched
dynamically, period. During the runtime binding, all the static types
of your arguments are known (emphasis mine), and types are picked for the dynamic
arguments based on their actual values.
So the fact that your method takes a Func isn't take into account, since the actual method call isn't determined until runtime so there is no type inference.
To get this to compile you'll have to cast your lamba to a Func<dynamic, string> as below:
return ifNotNull<string>(firstAddress, new Func<dynamic, string>((a) => a.address_1), null);
Now the static type of your lamda is known.

I meant that you need to cast the lambda method to the expect expression you want. Then it'll work just fine.
Like this:
return ifNotNull(firstAddress, (Func<dynamic, string>)((a) => a.address_1), null);

Related

Compiler error when using LINQ on IEnumerable<dynamic> but not if you cast it to IEnumerable<dynamic> first

OK, so I am writing some really messy code as the library I am working with is returning dynamic type hierarchies. Some of these types can be unfolded to lists of dynamic types and to enable me to work with these dynamic object hierarchies in LINQ I wrote a little method which basically transforms some dynamic objects to an IEnumerable<dynamic>.
I have this method that returns an IEnumerable<dynamic> but when I try to use it with LINQ I get the error "Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type.", however if I cast the methods return value from IEnumerable<dynamic> to IEnumerable<dynamic> (a no-op in my mind), it compiles and works fine.
Can anybody explain this behavior to me?
void Main()
{
Foo(null).Select(value => value); // OK... I was expecting this to work.
dynamic unknown = new ExpandoObject();
Foo(unknown).Select(value => value); //COMPILER ERROR: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type... this was a bit more unexpected.
((IEnumerable<dynamic>)Foo(unknown)).Select(value => value); // OK... this was really unexpected.
}
IEnumerable<dynamic> Foo(dynamic param)
{
yield return "Tranformation logic from param to IEnumerable of param goes here.";
}
The result of Foo(unknown) is dynamic, not IEnumerable<dynamic>. That's because the call to Foo is resolved dynamically, as unknown is dynamic.
To resolve Foo statically, you can write object unknown = new ExpandoObject();, or change the call to Foo((object) unknown).
What makes this worse is that extension methods are not supported on dynamic. Extension methods on IEnumerable<T> can be statically found even if T is dynamic, but the C# compiler does not provide a list of active using namespaces, so if you have plain dynamic, the runtime doesn't know which classes to search for extension methods. Even if .Select(value => value) could be made to compile, perhaps by turning it into Func<dynamic, dynamic> projection = value => value; and then unknown.Select(projection) (untested), it would still throw an exception at run-time. You'd need to explicitly write Enumerable.Select(unknown, projection) to make it work.

dynamic method invocation in expression tree

When constructing an expression tree, I have to use nodes invoking external methods in order to obtain values the expression could then continue evaluation with.
These methods are supplied as Func<T> and my code has no knowledge of where they originate from.
What is the most correct way of performing the mentioned invocation? I've tried something like this:
private Dictionary<string, Delegate> _externalSymbols;
private Expression _forExternalSymbol(string identifier)
{
Delegate method = _externalSymbols[identifier];
return Expression.Call(method.Method);
}
which works as long as the method fetched from the dictionary was created in compile-time. However, in case of Func<T> being a dynamic method obtained, for instance, by compiling another expression in runtime, this won't work out throwing
ArgumentException: Incorrect number of arguments supplied for call to method 'Int32 lambda_method(System.Runtime.CompilerServices.ExecutionScope)'
The desired effect may be achieved by wrapping the given function into one extra expression, but that seems quite hideous comparing to what it used to look like:
private Expression _forExternalSymbol(string identifier)
{
Delegate method = _externalSymbols[identifier];
Expression mediator = method is Func<double> ?
(Expression)(Expression<Func<double>>)(() => ((Func<double>)method)()) :
(Expression<Func<string>>)(() => ((Func<string>)method)());
return Expression.Invoke(mediator);
}
Also, this is hardly an extensible approach should I need to add support for types other than double and string.
I would like to know if there are better options which would work with dynamically created methods (preferably applicable to .NET 3.5).
which works as long as the method fetched from the dictionary was created in compile-time
No, it works as long as the method is static. For example, it also won't work if the delegate is a lambda that references something from its parent score (i.e. it's a closure).
The correct way to invoke a delegate is to use Expression.Invoke(). To get an Expression that represents your delegate, use Expression.Constant():
Expression.Invoke(Expression.Constant(method)))

What is the difference between Func<string,string> and delegate?

I see delegates in two forms:
A. Func<string, string> convertMethod = lambda
B. public delegate string convertMethod(string value);
I'm uncertain of what actually the difference between these two are. Are they both delegates? I believe the first one would use a lambda and the second would have to have a method to actually perform the work. I may be confused too.
First of all, your two examples are doing two totally separate things. The first is declaring a generic delegate variable and assigning a value to it, the second is just defining a delegate type. Your example, more completely, would be:
public static class Program
{
// you can define your own delegate for a nice meaningful name, but the
// generic delegates (Func, Action, Predicate) are all defined already
public delegate string ConvertedMethod(string value);
public static void Main()
{
// both work fine for taking methods, lambdas, etc.
Func<string, string> convertedMethod = s => s + ", Hello!";
ConvertedMethod convertedMethod2 = s => s + ", Hello!";
}
}
But more to the point, both Func<string,string> and delegate string convertMethod(string) would be capable of holding the same method definitions whether they be methods, anonymous methods, or lambda expressions.
As for which you should use, depends on the situation. If you want your delegate to be defined more by what it takes and returns, then the generic delegates are perfect. If you want the delegate to have some special name that gives more definition of what that delegate should do (beyond simple Action, Predicate, etc) then creating your own delegate is always an option.
The code sample you have is confusing things a bit so let me try and clear it up. The following 2 items are delegate declarations. These are easy to spot because they will always contain the delegate keyword
public delegate TReturn Func<TArg, TReturn>(Targ value);
public delegate string convertMethod(string value);
This line of code is assigning a value to a local which is typed to a delegate
Func<string, string> local = lambda;
The above code is not limited to using just lambdas though. The value could also be a compatible method group or another delegate value.
One other item to note is that even though Func<string, string> and convertMethod are both delegates with identical signatures their values are not convertible to each other. For example the following is illegal
Func<string, string> local1 = ...;
convertMethod local2 = local1; // Error!!!
From MSDN,
In versions of C# before 2.0, the only way to declare a delegate was
to use named methods. C# 2.0 introduced anonymous methods and in C#
3.0 and later, lambda expressions supersede anonymous methods as the
preferred way to write inline code.
and
There is one case in which an anonymous method provides functionality
not found in lambda expressions. Anonymous methods enable you to omit
the parameter list. This means that an anonymous method can be
converted to delegates with a variety of signatures.
You may also be interested in this SO answer on delegate keyword vs lambda expression.
Additionally, MSDN has a good article on Lambda Expressions:
delegate int del(int i);
static void Main(string[] args)
{
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
}
In the previous example, notice that the delegate signature has one
implicitly-typed input parameter of type int, and returns an int. The
lambda expression can be converted to a delegate of that type because
it also has one input parameter (x) and a return value that the
compiler can implicitly convert to type int. (Type inference is
discussed in more detail in the following sections.) When the delegate
is invoked by using an input parameter of 5, it returns a result of
25.
A initializes an instance of a delegate (that can be called immediately). It's a variable of type Func< string, string >.
B specifies the definition of a delegate (its signature). It can be used to later define variables of type convertMethod.

Defining a lambda expression with an anonymous type contained within that lambda

I'm trying to avoid a dynamic type in my lambda expression for grouping a collection. The type is defined anonymously at compile time (and unambiguously as far as I can tell). I'd rather not define the type as a full-fledged class as I'm only using it a few times in this single method.
Sample code:
Func<MyData, dynamic> dataGrouping = md => new
{
md.Property1,
md.Property2,
md.Property3
};
var groupedData = myDataCollection.GroupBy(dataGrouping);
While this will compile, it leaves me with no intellisense or strong typing inside the group as the type is dynamic.
I can't specify the type of dataGrouping as var, because I'm in C# and I get complaints of Cannot assign lambda expression to implicitly typed local variable.
Could I replace dynamic with the result of GetType() on the anonymous type? I'd then need the type before it's used in the lambda, but I can't see a useful way to get a handle on it before I'm already into the lambda itself.
Is there an elegant way of getting the type of this anonymous class?
Is there any reason you don't want to put the lambda expression directly in the GroupBy call? That's the way it all usually hangs together:
var groupedData = myDataCollection.GroupBy(md => new
{
md.Property1,
md.Property2,
md.Property3
});
You could make this work with an extra method:
static Func<TSource, TResult> CreateFunction<TSource, TResult>
(Func<TSource, TResult> function)
{
return function;
}
and then use type inference:
var dataGrouping = CreateFunction((MyData md) => new
{
md.Property1,
md.Property2,
md.Property3
});
Note how I've explicitly typed the parameter so that type inference has something to work with. That will work, but it's a bit ugly. I would embed the lambda expression directly in the method call unless you have any particular reason not to.

Generic Methods in C#

Generic Methods in general are new to me. Need a method that returns a Collection of a generic type, but also takes a collection of the same generic type and takes
Expression<Func<GenericType, DateTime?>>[] Dates
parameter. T throughout the following function should be the same type, so right now I was using (simplified version):
private static Collection<T> SortCollection<T>(Collection<T> SortList, Expression<Func<T, DateTime>>[] OrderByDateTime)
{
return SortList.OrderBy(OrderByDateTime[0]);
}
but i'm receiving error:
Error: The type arguments for method
'System.Linq.Enumerable.OrderBy(System.Collections.Generic.IEnumberable,
System.Func)' cannot be
inferred from the usage. Try
specifying the type arguments
explicitly.
Is there anyway to do this?
Sorry for answering twice, but this is legitimately another solution.
You're passing in an Expression<Func<T, DateTime>> but Orderby wants a Func<T, DateTime>
You can either compile the expression:
return new Collection<T>(SortList.OrderBy(OrderByDateTime[0].Compile()).ToList());
or pass in straight out funcs as arguments:
private static Collection<T> SortCollection<T>(Collection<T> SortList, Func<T, DateTime>[] OrderByDateTime)
{
return new Collection<T>(SortList.OrderBy(OrderByDateTime[0]).ToList());
}
I'd recommend reading up on Expressions on msdn
In this situation, the compiler is failing to figure out what type arguments you intend to provide to the OrderBy method, so you'll have to supply them explicitly:
SortList.OrderBy<T, DateTime>(OrderByDateTime[0])
You'll probably want to call ToList() if you want a Collection to be returned

Categories

Resources