How do delegate/lambda typing and coercion work? - c#

I've noticed some examples of things that work and don't work when dealing with lambda functions and anonymous delegates in C#. What's going on here?
class Test : Control {
void testInvoke() {
// The best overloaded method match for 'Invoke' has some invalid arguments
Invoke(doSomething);
// Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type
Invoke(delegate { doSomething(); });
// OK
Invoke((Action)doSomething);
// OK
Invoke((Action)delegate { doSomething(); });
// Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
Invoke(() => doSomething());
// OK
Invoke((Action)(() => doSomething()));
}
void testQueueUserWorkItem() {
// The best overloaded method match for 'QueueUserWorkItem' has some invalid arguments
ThreadPool.QueueUserWorkItem(doSomething);
// OK
ThreadPool.QueueUserWorkItem(delegate { doSomething(); });
// The best overloaded method match for 'QueueUserWorkItem' has some invalid arguments
ThreadPool.QueueUserWorkItem((Action)doSomething);
// No overload for 'doSomething' matches delegate 'WaitCallback'
ThreadPool.QueueUserWorkItem((WaitCallback)doSomething);
// OK
ThreadPool.QueueUserWorkItem((WaitCallback)delegate { doSomething(); });
// Delegate 'WaitCallback' does not take '0' arguments
ThreadPool.QueueUserWorkItem(() => doSomething());
// OK
ThreadPool.QueueUserWorkItem(state => doSomething());
}
void doSomething() {
// ...
}
}
Well that's a lot of examples. I guess my questions are the following:
Why does Invoke always refuse a lambda function or an anonymous delegate, yet ThreadPool.QueueUserWorkItem does just fine?
What the heck does "Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type" mean anyway?
Why does ThreadPool.QueueUserWorkItem accept an anonymous delegate with no parameters, but not a lambda expression with no parameters?

ThreadPool.QueueUserWorkItem has a specific delegate in its signature; Invoke just has Delegate. Lambda expressions and anonymous methods can only be converted to a specific delegate type.
It's just a bad error message. It means, "I don't know exactly which delegate type you're trying to convert to."
You're using an anonymous method without a parameter list at all which can be converted to any delegate type which doesn't use out/ref parameters. If you tried delegate() { ... } (i.e. an explicitly empty parameter list) then it wouldn't work. This "I don't care about parameters" ability of anonymous methods is the only feature they have which lambda expressions don't.
It's easiest to demonstrate all of this in the context of simple assignments, IMO:
// Doesn't work: no specific type
Delegate d = () => Console.WriteLine("Bang");
// Fine: we know the exact type to convert to
Action a = () => Console.WriteLine("Yay");
// Doesn't work: EventHandler isn't parameterless; we've specified 0 parameters
EventHandler e1 = () => Console.WriteLine("Bang");
EventHandler e2 = delegate() { Console.WriteLine("Bang again"); };
// Works: we don't care about parameter lists
EventHandler e = delegate { Console.WriteLine("Lambdas can't do this"); };

Related

How to change delegate expression to lambda?

I was reading some code and saw the following:
Method.Find(delegate(Department depts) {
return depts.Id == _departmentId; });
The T Find method has the following description:
public T Find(Predicate<T> match);
// Summary:
// Searches for an element that matches the conditions defined by the specified
// predicate, and returns the first occurrence within the entire
// System.Collections.Generic.List<T>.
//
// Parameters:
// match:
// The System.Predicate<T> delegate that defines the conditions of the element
// to search for.
// (...)
Is it possible to rewrite this method to take a lambda expression as a parameter, and if so, how?
The method can already accept a lambda expression as a parameter, if you want to pass one to it.
The method simply indicates that it accepts a delegate. There are several ways of defining a delegate:
A lambda (Find(a => true))
An anonymous delegate (what you used in your example)
A method group Find(someNamedMethod)
Reflection (Find((Predicate<Whatever>)Delegate.CreateDelegate(typeof(SomeClass), someMethodInfo)))
No need to re-write the method, you can use a lambda already, as below:
Method.Find(x => x.Id == _departmentId );
The code you provide is an anonymous delegate
Method.Find(delegate(Department depts) {
return depts.Id == _departmentId; });
a lambda is an anonymous function.

Extension method on lambda expression

I have a helper method which gets the name of a property defined by a lambda which works as below:
ExpressionUtil.GetName((Thing t) => t.Property); // returns "Property"
I would like to turn this into an extension method so the syntax would be of the form:
((Thing t) => t.Property).GetName(); // wont compile : operator '.' cannot be applies to operand of type 'lambda expression'
However I cant seem to do this as ((Thing t) => t.Property) is a lambda (not an expression or Func yet). Is there any way to write an extension method which applies directly to a lambda? If not why is this a bad thing to do?
You can't do that, because a lambda expression has no type by itself; its type is determined by the context (e.g. if you assign it to a delegate variable or pass it as an argument to a method).
Since ((Thing t) => t.Property) doesn't have a type, you can't call an extension method on it, because the compiler doesn't know which extension methods are valid candidates.
You can, however, declare a variable and call the extension method on it:
Func<Thing, OtherThing> func = t => t.Property;
string name = func.GetName();
you may create an extension method on an Action at the low cost of having a introducing instantiation.
I sometimes use it and the code is readable.
The reason this code exists is less elegant, a rotten NAS :-[
new Action(() =>
{
if (File.Exists(newFullPath))
File.Delete(newFullPath);
File.Move(oldFullPath, newFullPath);
})
.Try(attemps: 2, exceptionValidator: (exception, attempt, attempts) =>
{
var throwIt = (attempt == attempts);
if (!throwIt)
Thread.Sleep(500);
// .. tracing ./. throw
return (throwIt);
});
Just in case ... even if post not young.

C# Lambda Functions: returning data

Am I missing something or is it not possible to return a value from a lambda function such as..
Object test = () => { return new Object(); };
or
string test = () => { return "hello"; };
I get a build error "Cannot convert lambda expression to type 'string' because it is not a delegate type".
It's like this syntax assigns the lambda rather than the result of the lambda, which I did not expect.
I can achieve the desired functionality by assigning the function to a Func and calling it by name, but is that the only way?
Please no "why would you need to do this?" regarding my example.
Thanks in advance!
It’s possible but you are trying to assign a lambda to a string. – You need to invoke the lambda:
Func<string> f = () => { return "hello"; };
string test = f();
The error message actually says it all:
Cannot convert lambda expression to type 'string'
… that’s exactly the issue here.
If you want to invoke the lambda inline – but really: why? – you can do that too, you just need to first make it into a delegate explicitly:
string test = (new Func<string>(() => { return "hello"; }))();

cross thread invoke compilation problem

Can anyone advise why this line of code would not compile? It generates CS1660 instead:
s.run_button.Invoke((b) => { b.Enabled = false; },
new object[] { s.run_button });
Visual studio says: Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
Lambda expressions by themselves have no type and are not convertible to System.Delegate. The Invoke method has the type System.Delegate and hence it won't compile because the lambda expression has no type. You need to provide an explicit type conversion here
s.run_button.Invoke(
(Action<Button>)((b) => { b.Enabled = false; }),
new object[] { s.run_button });
The Invoke method takes a parameter of type Delegate. It was written before lambdas entered our world. The easiest solution for you is to wrap your lambda with an Action. I'm not sure precisely what type "b" is (and neither does the C# compiler, hence the error), so you'll have to pass it in explicitly. Something like:
s.run_button.Invoke(new Action<Button>(b => b.Enabled = false), new object[] { s.run_button });

What does this mean in C# or LINQ? - ( () => )

I was going through Jeffrey Palermo's book and came across this syntax.
private void InitializeRepositories()
{
Func<IVisitorRepository> builder = () => new VisitorRepository();
VisitorRepositoryFactory.RepositoryBuilder = builder;
}
What does it mean?
() => indicates a lambda expression that takes no arguments.
In general, it means a function with no arguments.
In this particular example, it creates an anonymous function with no arguments that returns a new VisitorRepository(); object every time.
Func<IVisitorRepository> stands for a delegate which takes no arguments and returns a IVisitorRepository. The creation of that delegate is a lambda function:
() //means no parameters
=> new VisitorRepository()// means it returns a new VisitorRepository
() is the place where you place your variables
Example a common event handled would look like (sender, args)
=> // means throw these parameter into this method
after => you can either drop a one line execution thing like new VisitorRepositor()
OR
you can place a whole function like
Func<IRepository> = (sender, args) =>
{
var myObject = (SomeObject)sender;
return new VisitorReposiroty { id = myObject.SomeId };
}
As other stated it's lambda expression and it really clears your code from method or function that handle a specific event.
Once you read them good it's really damn useful.
The () => syntax is a lambda expression. Lambdas were introduced in C# 3.0 and are used to define an anonymous method for a delegate.
The delegate is defined using the generic Func. So in this case the signature for the delegate is: no input parameters and one output parameter of type IVisitorRepository.
So on the left side of the => lambda array are the names of the input parameters. In case of no input parameters just write (). On the rightside of the => lambda is the code to return the output parameter, in this example: new VisitorRepository().
I suggest read more about lambda expressions in C# to fully understand this code. There is also a generic delegate involved, so you need understanding of Generics and Delegates as well.
Func is a delegate without parmeter and with an IVisitorRepository return value.
() => is a lambda expression creating an anonymous method.
new VisitorRepository() is the content of this anonymous method.
so this line is creating a delegate which is pointing to a anonymous method, which is returning an instance of VisitorRepository.
Func<IVisitorRepository> builder = () => new VisitorRepository()
In the next line, you set the value of a static property to this just created delegate.
VisitorRepositoryFactory.RepositoryBuilder = builder;
After this you can use the property to call the anonymous method, which is creating a new instance of VisitorRepository.
IVisitorRepository repository = VisitorRepositoryFactory.RepositoryBuilder();
In this case, repository will be an instance of VisitorRepository.
It means a function takes no parameters, like:
delegate() {//}

Categories

Resources