maverick maverick - 12 days ago 9
C# Question

Can not use a simple Action<Object> delegate to register cancellation

According to the content I am reading, I should be able to register a delegate of type Action to be executed upon cancelation, but the complier gives me and error stating: 'DisplayMessage' delegate can not be used in the current context. I can not tell what I am doing wrong.
Here is the code commented in the area, which I get the error...

I updated the code, and while Console.Writeline works, calling a message box method gives me an error stating can not convert from method group to Action delegate. Here is the updated code:

edit: The last functionality I was after was to call an actual method, one that perhaps has slightly different signature from Action. The following modification kind of works, except it prints the Window twice. I do not get why it is doing that since I am copying every line from the relevant Console.WriteLine lines in my code. I realized that I had a type mismatch between the method I wrote and what Register method accepts which is Action. Now I am basically trying to figure out what I get two MessageBoxs when the method signatures are the same, and the code is the same.

Thank you for everyone's feedback. The following code works the way I wanted. It is commented, and I am posting it in case someone else likes to do something similar.

using System;
using System.Threading;
using System.Windows.Forms;

namespace CancellationSource
{
internal delegate void DisplayMessage(string message);
internal static class Program
{
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 50));
//ThreadPool.QueueUserWorkItem(o => Count(CancellationToken.None, 50));
Console.WriteLine("Press <enter> to cancel the operation.");
Console.ReadLine();

Action<Object> messageTarget;
messageTarget = Console.WriteLine;
cts.Token.Register(Console.WriteLine, null, true);
messageTarget = ShowWindowsMessage;
messageTarget ("This should print in box");
//This code opens a
//Message box only when the called thread operation is cancelled. This code calls two different methods
//of type Action<Object> when the spawned / requested thread is canceled.
//cts.Token.Register(messageTarget, null, true);
cts.Cancel();
Console.ReadLine();
}
//Notice in order to get the method below to execute upon thread cancelation, I had to make sure its
//its signature is one of Action<Object>
private static void ShowWindowsMessage(object value)
{
var message = (string)value;
MessageBox.Show(message);
}

private static void Count(CancellationToken token, Int32 countTo) {
for (int count = 0; count < countTo; count++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Count is cancelled");
break;
}
Console.WriteLine(count);
Thread.Sleep(200);
}
Console.WriteLine("Count is done");
}
}

}

Answer

If you are not using the state object because you are passing null then you can take another overload of the Register method:

public CancellationTokenRegistration Register( Action callback, bool useSynchronizationContext )

and simply call it like this:

cts.Token.Register(new Action(() => { Console.WriteLine("Hello World"); }), true);

If you want to stick to your delegate you can also use this:

cts.Token.Register(()=> messageTarget("Hello, World!"), true);

EDIT:

If Register() demands an Action<object> delegate than you could just use this type and pass only the delegate name:

Action<object> messageTarget;
messageTarget = Console.WriteLine;
messageTarget("Hello, World!");
cts.Token.Register(messageTarget, null, true);
Comments