cross thread invoke compilation problem - c#

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 });

Related

How to handle Closure and Static Method Call in Expression Tree?

The Following Code tries to Create a Func delegate that converts from the original func Argument Type to another type.
public static Delegate Convert<T1, R>(this Func<T1, R> func, Type argType)
{
var param = Expression.Parameter(argType);
var convertedParam = new Expression[] { Expression.Convert(param, typeof(T1))};
var call = Expression.Convert(
func.Target == null || func.Target is Closure
? Expression.Call(func.Method, Expression.Constant(func.Target), convertedParam[0])// this path causes the error
: Expression.Call(Expression.Constant(func.Target), func.Method, convertedParam), typeof(R));
var delegateType = typeof(Func<,>).MakeGenericType(argType, typeof(R));
var lambda = Expression.Lambda(delegateType, call, param);
return lambda.Compile();// BUG: 'MethodInfo must be a runtime MethodInfo object.
}
My problem starts when the Func contains a closure as Target, lambda.Compile() bugs saying "Method Info must be a runtime MethodInfo Object" i suspect it's because the method is static.
Can someone please explain to me what i am doing wrong? and why? i obviously don't understand Expressions well enough to fix this on my own.
Thanks in advance.
You should call Expression.Invoke, which will call a delegate directly.
Pass it Expression.Constant(func).

Delegate.Combine and lambda expression

Suppose i have this delegate's declaration:
private delegate UInt32 Feedback(UInt32 value);
And here i try to use it with lambda expression
feedback = (Feedback)Delegate.Combine(feedback,
value => { Console.WriteLine("Lambda item = " + value); return 0; });
But i get error: Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
But it works this way
feedback = (Feedback)Delegate.Combine(feedback,
new Func<UInt32, UInt32>(value => { Console.WriteLine("Lambda item = " + value); return 0; }));
I have thought that C# compiler must do it itself.
feedback = (Feedback)Delegate.Combine(feedback,
(Feedback)(value => { Console.WriteLine("Lambda item = " + value); return 0; }));
You must explicitly say the type of a lambda function, otherwise the compiler doesn't know what type it has. For example see http://blogs.msdn.com/b/jaredpar/archive/2007/12/14/c-lambda-type-inference.aspx
One of the limitations of C# type inference is that you cannot use it to infer the type of a lambda expression. For example, the following code will not compile
var f = () => 4;
Lambda expressions do not have type in C# unless you cast them.It's because one lambda can be convertible to more than one delegate type so compiler can't decide which one to choose.And also there is no way to determine what are the type of lamda arguments since you are not specifying them.
Lambda doesn't have a type. It is implicitly convertible to compatible delegate type.
Delegate.Combine takes Delegate as parameter, Since Delegate is an abstract class without any signature, lambda expressions cannot be converted into Delegate. You can only convert a lambda to a concrete type which has a compatible signature.
If you expect the compiler to convert your lambda to Delegate type which is an abstract class and thus can't be instantiated --Which concrete type you would like the compiler to choose? You'll have to specify it.
You can specify the type explicitly like this:
feedback = (Feedback)Delegate.Combine(feedback, new Feedback(value => { Console.WriteLine("Lambda item = " + value); return 0; }));
On the other hand if you have the concrete delegate type in LHS, compiler will be happy to compile.
For example: Following is a valid c# code. Because you said the compiler that you need to convert it to Feedback delegate type.
Feedback feedback2 = value => { Console.WriteLine("Lambda item = " + value); return 0; };

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"; }))();

How do delegate/lambda typing and coercion work?

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"); };

how to set Anonymous delegate as one parameter for InvokeSelf?

I tried to use InvokeSelf for silverlight to communicate with html:
InvokeSelf can take object[] as parameter when making a call:
ScriptObject Myjs;
ScriptObject obj = Myjs.InvokeSelf(new object[] { element }) as ScriptObject;
then I want make a call like with anonymous delegate:
Object obj;
obj = InvokeSelf(new object[] { element, delegate { OnUriLoaded(reference); } });
I got the error said:
Cannot convert anonymous method to type 'object' because it is not a delegate type
How to resolve this problem?
The problem is that you cannot assign an anonymous method to an object. This is because the C# compiler doesn't know what delegate type should be used. You can fix the code by creating a delegate explicitly. Since this is Silverlight you can also use more succinct lambda expression notation:
obj = InvokeSelf(new object[]
{ element, new Action(() => OnUriLoaded(reference)) });
That said, I'm not sure if it is possible to pass a delegate to JavaScript, but you should be able to compile the code now and try that.

Categories

Resources