Why Must a Lambda Expression Be Cast When Supplied as a Plain Delegate Parameter

Why must a lambda expression be cast when supplied as a plain Delegate parameter

A lambda expression can either be converted to a delegate type or an expression tree - but it has to know which delegate type. Just knowing the signature isn't enough. For instance, suppose I have:

public delegate void Action1();
public delegate void Action2();

...

Delegate x = () => Console.WriteLine("hi");

What would you expect the concrete type of the object referred to by x to be? Yes, the compiler could generate a new delegate type with an appropriate signature, but that's rarely useful and you end up with less opportunity for error checking.

If you want to make it easy to call Control.Invoke with an Action the easiest thing to do is add an extension method to Control:

public static void Invoke(this Control control, Action action)
{
control.Invoke((Delegate) action);
}

Why when I implement a lambda expression in the main method, the compiler doesn't say the interfaces are implemented?

All you have done is define local variables in the main method whose type happens to coincide with the interfaces that the class must implement.

You must define methods in the class that provide implementations for all the interfaces of the class. For example:

public class Driver implements Interface1, Interface2, Interface3 {
public static void main(String[] args) {
// all code in here is irrelevant to the class implementing Interface1, Interface2, Interface3
}

public void interface1Method() {
// whatever
}

public void interface2Method() {
// whatever
}

public void interface3Method() {
// whatever
}
}

Note that you can't use lambdas for this; Driver must actually declare implementations for the missing methods from all the interfaces its declares it is implementing.

Cannot convert lambda expression to type 'System.Delegate', Because it is not a delegate type

IMHO, it is generally better to address cross-thread needs outside of individual properties. The properties themselves should be simple, just calling GetValue() and SetValue(). In other words, a property getter or setter should not need to call Dispatcher.Invoke() at all.

That said, in your code example, you are seeing the error you're asking about in the property getter, because the compiler does not have enough information to infer the correct delegate type. The Dispatcher.Invoke() method simply takes as its parameter the base class Delegate. But this class has no inherent signature, which the compiler would need in order to automatically translate the lambda expression to an appropriate anonymous method and matching delegate instance.

Note that there is not a similar error in the setter. This is because you have provided the delegate type explicitly, through the use of the Action type's constructor. If you change the getter code to look more like the setter, it will work.

There are a few different syntaxes you could choose from, but this seems closest to the syntax you seem to prefer, based on the setter:

get
{
return Dispatcher.Invoke(
new Func<object>(() => GetValue(class1Property))) as Class1;
}



See related discussion at e.g. Why must a lambda expression be cast when supplied as a plain Delegate parameter (if you search Stack Overflow for the error message you're seeing, you'll find a few related questions).

Delegate isn't working like I think that it should be (Lambda Expression is not working)?

This isn't a problem with the lambda expression. Your Test method expects 5 parameters, 1 delegate, and 4 strings, but you've only provided a delegate and 2 strings.

Try providing 2 more, and it will work:

Console.WriteLine(Test( (input1, input2, input3, input4) => ..., 
"look at this",
"How do you do!",
"another string",
"yet another string")

Why do I need to cast a List T of a declared List T when passing through a Lambda OrderBy expression?

The lambda in itself is irrelevant here, the key is LINQ behavior.

The OrderBy extension method does NOT order your list as you think. Instead, it creates a new, independent IEnumerable<T> with the result of the sorting, leaving the original untouched. So it's not a List<T>, but a completely different type, whose only capability is to be enumerated, following the order you asked for.

A List is that and also a couple more things (irrelevant for now), but the important thing is that the return value of OrderBy is not a list. The proposed cast is also wrong just because of that, as you're trying to cast an IEnumerable<T> to List<T>. In general, those casts may or may not work, depending on the real underling type (as IEnumerable<T> is an interface, compared to List<T> being a concrete class), so the compiler allows it. In the particular case of LINQ's OrderBy it'll certainly fail, as it doesn't returns a list at all.

To actually get a list, you can use yet another LINQ method, ToList:

List<DirectoryObjects> sort = dirObjList.OrderBy(ms => ms.name).ToList();

This will iterate the original collection, sort it as you want, and store the result in a new List<T> object.

Misunderstanding of .NET on overloaded methods with different parameters (Call Ambiguous)

Lambda expressions (x=> x.Id==1) do not have type by themselves - they automatically "cast" to Expression or Func/delegate of matching type when type is known. I.e. Why must a lambda expression be cast when supplied as a plain Delegate parameter deals with similar issue just between different delegate types.

In your case methods that are potential candidate suggest both variants and compiler can't make a choice.

If you really have to keep same name then callers will have to specify type themselves:

 myRepo.GetData((Expression<Func<TEntity, Boolean>>)(x => x.Id == 1));
myRepo.GetData((Func<TEntity, Boolean>)(x => x.Id == 2));

I don't think you can use extension method for one of alternatives as search will stop at the class level. So really having methods with different names is the only real option (if you need both). Consider if just Expression version is enough. Alternatively you can split them between different classes (similar how extensions of IQueryable take Expression when similar methods on IEnumerable take Func (see QueryableExtenasions).

Why can't c# use inline anonymous lambdas or delegates?

Lambdas in C# do not have types, until they are used in a context that casts them to a delegate or Expression type.

That's why you cannot do the following:

var x = () => "some lambda";

You might enjoy Eric Lippert's Series on Lambda Expressions vs Anonymous Methods

  • Lambda vs Anon - Part One
  • Lambda vs Anon - Part Two
  • Lambda vs Anon - Part Three
  • Lambda vs Anon - Part Four
  • Lambda vs Anon - Part Five


Related Topics



Leave a reply



Submit