On May 30, 1:31 am, "Peter Duniho" <
[email protected]>
wrote:
I understand the example you give, but not how it relates.
I'll attempt to make things clearer
While the compiler is complaining about not being able to perform
inference on the type, it's my opinion that the expression "(int iElement)
=> return rnd.Next(integers.Count);" needs no additional information.
It does. That expression in itself doesn't have a known type. It can
be converted to a delegate type in itself.
This is borne out by the fact that using that directly in the OrderBy()
method works fine. (Note: I realize this isn't actually true...it's just
how I think it _ought_ to be...see below).
The reason it works for OrderBy is that OrderBy's parameter is a
Func<TSource,TKey> (or something similar - I've lost my network
connection at the minute). It can convert
(iElement) => "foo"
into a Func<int, string> very easily. However, when you put in an
extra level of lambda expressions, it won't manage it - if you call
OrderBy(first => (second => "foo"))
you'll get the same type inference problem - it can't infer the TKey
type.
(It's possible you understood all of this bit already - just thought
I'd restate it for clarity.)
It seems to me that the real issue here is how the expansion works, in
that it's a straight "search and replace" sort of expansion in which a
lambda expression is simply not an appropriate input.
It's not an appropriate input when the compiler needs to do type
inference. If you wrote a type with the appropriate LINQ operators
where OrderBy was declared to accept a
I (think) I get why the compiler says what it says. Different parts of
the compiler are probably responsible for different parts of the process;
there's effectively a pre-processor doing the "search and replace" part,
and by the time that then is tried to be compiled into IL, it's not only
just plain wrong, there's no enough type information for any inference to
be done. Hence the actual error message.
Sort of. The query expression expansion part is indeed relatively
plain. But I don't think that's the root cause - the root cause is the
inability to infer a whole type directly from a lambda expression (as
opposed to inferring some of the parameter types or the return type,
based on knowledge of the general shape of what it's meant to be
converted to).
So, sure...the cast is required...but the real gimmick in the code you
posted is the final "()" that actually _calls_ the delegate. That changes
the lambda expression, after casting, into something that can then be
inserted into yet another lambda expression for actual evaluation. Even
with a cast, a lambda expression by itself wouldn't work.
It wouldn't actually *work*, but I think it would compile.
Finally, I do admit to remaining a little confused about the lack of type
inference for un-cast delegates (this is the "see below" I mentioned
). In particular, I'm not really sure why the language won't create some
sort of implicit delegate type for the purposes of doing type inference.
A common statement is one that looks like:
myControl.Invoke((MethodInvoker) delegate { // some code });
The cast is required because of the reason you state. But Invoke()
actually just takes a Delegate. Why can't the compiler generate an
anonymous type (sort of like it does with "var") that can then be used?
Just to be clear for any other readers - it's not "var" that creates
anonymous types, it's expressions of the form new { Property =
Value }. "var" is just how you cope with the fact that you can't tell
the compiler what the type's name is. You can in fact use anonymous
types without var, and var without anonymous types.
However, yes, it would be possible for the compiler to create a new
delegate type for you - or try to use one of the existing generic
ones, as mentioned before. Personally I don't think the extra
complexity in the language (particularly with respect to overloading -
there are a few nasty cases I can think of off-hand) but I would
imagine it would be doable.
It's not like the compiler doesn't know the method signature, is it? I
mean, I _think_ it should know the signature...if there's some reason it
doesn't, it's not obvious to me.
In the MethodInvoker example you gave it knows one potential
signature. It doesn't know what parameters it could use, because
you've used the syntax which says "I don't care about parameters."
With the more explicit syntax (e.g. delegate() { ... }) it would have
more information.
Jon