How to declare and await an async delegate? - c#

For some reason, despite this question coming up a lot in my googling, I can't seem to find an actual answer. Maybe I'm just using delegates wrong, I'm not sure. I'm happy for alternative ways of handling this if it's an X-Y problem.
Say I have this:
public class SomeLibrary
{
public delegate void OnSomethingHappened(EventInfo eventInfo);
public OnSomethingHappened onSomethingHappened;
public void SomeMethod()
{
// ...
// Something happened here, so we'd better trigger the event
onSomethingHappened?.Invoke(eventInfo);
// ...
}
}
public class MyCode
{
public void SomeInitialisationMethod()
{
SomeLibrary someLibrary = new SomeLibrary();
someLibrary.onSomethingHappened += SomeEventHandler;
}
private void SomeEventHandler(EventInfo eventInfo)
{
DoSyncProcessing(eventInfo);
}
}
That should all be fine (barring silly typos).
Now imagine my regular synchronous DoSyncProcessing function suddenly has to become asyncronous, like in this magic non-functional code:
public class SomeLibrary
{
public async delegate Task OnSomethingHappened(EventInfo eventInfo); // <<< IDK what I'm doing here!
public OnSomethingHappened onSomethingHappened;
public void SomeMethod()
{
// ...
// Something happened here, so we'd better trigger the event
await onSomethingHappened?.Invoke(eventInfo); // <<< IDK what I'm doing here either!
// ...
}
}
public class MyCode
{
public void SomeInitialisationMethod()
{
SomeLibrary someLibrary = new SomeLibrary();
someLibrary.onSomethingHappened += SomeEventHandler;
}
private async Task SomeEventHandler(EventInfo eventInfo)
{
await DoAsyncProcessing(eventInfo);
}
}
How can I handle that? What's the correct way to do this?

The async modifier affects the method implementation, not the signature. So change this:
public async delegate Task OnSomethingHappened(EventInfo eventInfo);
To this:
public delegate Task OnSomethingHappened(EventInfo eventInfo);
and your code will work.

Related

Trigger and handle Event async

I'm currently working on a .net 5 Blazor application.
I use events to pass data from one component to another.
Unfortunately my current logic is synchronous - but I would rather use an asynchronous event handler.
Thus, I need to use the following code to handle my event:
Task.Run(async () => await ChangeNumbers());
Is there a possibility to handle events asynchronously without Task.Run?
My State service looks like this:
public class MyComponentState
{
public int MyNumber { get; set; }
// Is there a way to declare this event Action async??
public event Action OnChange;
public void DoStuff(int myNumber)
{
MyNumber = myNumber;
NotifyStateChanged();
}
private void NotifyStateChanged() => OnChange?.Invoke();
}
The component to handle the state looks like this:
public class MyOtherComponentDisplay : ComponentBase, IDisposable
{
[Inject]
public MyComponentState MyComponentState { get; set; }
protected override void OnInitialized()
{
// this should all be handled async... i could use OnInitializedAsync
MyComponentState.OnChange += OnChangeHandler;
}
private void OnChangeHandler()
{
// Is there a way to handle/declare this without Task.Run(async ...) - but async right away??
Task.Run(async () => await ChangeNumbers());
}
private async Task ChangeNumbers()
{
// Some operations with MyComponentState.MyNumber async needed!!!
StateHasChanged();
}
public void Dispose()
{
MyComponentState.OnChange -= OnChangeHandler;
}
}
Is there a way to declare and handle events async?
Do you know how to solve this problem?
The basic adoptation would be an async void handler:
private async void OnChangeHandler()
{
// Is there a way to handle/declare this without Task.Run(async ...)
// - but async right away??
// Task.Run(async () => await ChangeNumbers());
await ChangeNumbers();
await InvokeAsync(StateHasChanged); // probably needed
}
The way you're doing things looks strange to me. That's not how I do events in Blazor. (Maybe you're coming from Web Forms?)
Generally, a custom event is defined like:
MyControl.razor
[Parameter]
public EventCallback<SomeType> EventName{ get; set; }
#code {
someMethod (){
EventName.InvokeAsync(SomeType data);
}
}
And the handler in the consuming control can be async if you want:
MyPage.razor
<MyControl EventName=OnChangeHandler />
#code {
private async Task OnChangeHandler()
{
await ChangeNumbers();
}
}

Force code to execute in order?

I am seeing a strange problem in my C# code. I have something like this:
public static class ErrorHandler {
public static int ErrorIgnoreCount = 0;
public static void IncrementIgnoreCount() {
ErrorIgnoreCount++;
}
public static void DecrementIgnoreCount() {
ErrorIgnoreCount--;
}
public static void DoHandleError() {
// actual error handling code here
}
public static void HandleError() {
if (ErrorIgnoreCount == 0) {
DoHandleError();
}
}
}
public class SomeClass {
public void DoSomething() {
ErrorHandler.IncrementIgnoreCount();
CodeThatIsSupposedToGenerateErrors(); // some method; not shown
ErrorHandler.DecrementIgnoreCount();
}
}
The problem is that the compiler often decides that the order of the three calls in the DoSomething() method is not important. For example, the decrement may happen before the increment. The result is that when the code that is supposed to generate errors is run, the error handling code fires, which I don't want.
How can I prevent that?
Add Trace or Logs to your code in IncrementIgnoreCount, DecrementIgnoreCount and HandleError function.
That will help you to view real call order.

Execute Method Before and After Code Block

How could I wrap some code in brackets to do the following?
MyCustomStatement(args){
// code goes here
}
So that before the code in the brackets executes, it'll call a method and when the code in the brackets finishes executing it will call another method. Is there such a thing? I know it seems redundant to do this when I can simply call the methods before and after the code and all, but I simply was curious. I don't know how to word this exactly because I'm new to programming.
Thanks!
You can do this by storing the code in an abstract class that executes the "before" and "after" code for you when you call Run():
public abstract class Job
{
protected virtual void Before()
{
// Executed before Run()
}
// Implement to execute code
protected abstract void OnRun();
public void Run()
{
Before();
OnRun();
After();
}
protected virtual void After()
{
// Executed after Run()
}
}
public class CustomJob : Job
{
protected override void OnRun()
{
// Your code
}
}
And in the calling code:
new CustomJob().Run();
Of course then for every piece of custom code you'll have to create a new class, which may be less than desirable.
An easier way would be to use an Action:
public class BeforeAndAfterRunner
{
protected virtual void Before()
{
// Executed before Run()
}
public void Run(Action actionToRun)
{
Before();
actionToRun();
After();
}
protected virtual void After()
{
// Executed after Run()
}
}
Which you can call like this:
public void OneOfYourMethods()
{
// your code
}
public void RunYourMethod()
{
new BeforeAndAfterRunner().Run(OneOfYourMethods);
}
To literally achieve what you want, you can use a delegate:
Action<Action> callWithWrap = f => {
Console.WriteLine("Before stuff");
f();
Console.WriteLine("After stuff");
};
callWithWrap(() => {
Console.WriteLine("This is stuff");
});
This requires adding "weird syntax" to your blocks and an understanding of how delegates and anonymous functions in C# work. More commonly, if you're doing this within a class, use the technique demonstrated in #CodeCaster's answer.

Is There a C#.Net Equivalent to Objective-C's Selector

This is a C#.net question for Objective-C developers who also work with C#.Net
As you know, Objective-C you can parse a method name to a Selector; and the method can also belong to an outside class.
I would like to be able to use this type of method in C#.Net as it would be a lot cleaner than creating loads of Events which can become messy and hard to manage.
If this is possible, how can I achieve this? Thank you!
Example:
public class Main
{
public void MyProcess(Callback toMethod)
{
// do some fancy stuff and send it to callback object
toMethod(result);
}
}
public class Something
{
public void RunMethod()
{
MyProcess(Method1);
MyProcess(Method2);
}
private void Method1(object result)
{
// do stuff for this callback
}
private void Method2(object result)
{
// do stuff for this callback
}
}
I don't know Objective-C, but I think you want something like this:
public class Main
{
public void MyProcess(Action<object> toMethod, object result)
{
// do some fancy stuff and send it to callback object
toMethod(result);
}
}
public class Something
{
public void RunMethod()
{
object result = new object();
MyProcess(Method1, result);
MyProcess(Method2, result);
}
private void Method1(object result)
{
// do stuff for this callback
}
private void Method2(object result)
{
// do stuff for this callback
}
}
You would have to use Delegates. Based on the code in your question, you would declare a delegate:
public delegate void MethodDelegate(object result);
The signature of the process method changes to the following:
public void MyProcess(MethodDelegate toMethod)
{
// do some fancy stuff and send it to callback object
toMethod(result);
}
And then you would call process
public void RunMethod()
{
MyProcess(new MethodDelegate(Method1));
MyProcess(new MethodDelegate(Method1));
}

implementing delegates in c#

This would be the first time I'd use delegates in c# so please bear with me. I've read a lot about them but never thought of how/why to use this construct until now.
I have some code that looks like this:
public class DoWork()
{
public MethodWorkA(List<long> TheList) {}
public void MethodWork1(parameters) {}
public void MethodWork2(parameters) {}
}
I call MethodWorkA from a method outside the class and MethodWorkA calls MethodWork 1 and 2. When I call methodA, I'd like to pass some sort of parameter so that sometimes it just does MethodWork1 and sometimes it does both MethodWork1 and MethodWork2.
So when I call the call it looks like this:
DoWork MyClass = new DoWork();
MyClass.MethodA...
Where does the delegate syntax fit in this?
Thanks.
public void MethodWorkA(Action<ParamType1, ParamType2> method) {
method(...);
}
You can call it using method group conversion:
MethodWorkA(someInstance.Method1);
You can also create a multicast delegate that calls two methods:
MethodWorkA(someInstance.Method1 + someInstance.Method2);
For what you described, you don't need delegates.
Just do something like this:
public class DoWork
{
public void MethodWorkA(List<long> theList, bool both)
{
if (both)
{
MethodWork1(1);
MethodWork2(1);
}
else MethodWork1(1);
}
public void MethodWork1(int parameters) { }
public void MethodWork2(int parameters) { }
}
If you're just experimenting with delegates, here goes:
public partial class Form1 : Form
{
Func<string, string> doThis;
public Form1()
{
InitializeComponent();
Shown += Form1_Shown;
}
void Form1_Shown(object sender, EventArgs e)
{
doThis = do1;
Text = doThis("a");
doThis = do2;
Text = doThis("a");
}
string do1(string s)
{
MessageBox.Show(s);
return "1";
}
string do2(string s)
{
MessageBox.Show(s);
return "2";
}
}
Considering that all methods are inside the same class, and you call MethodWorkA function using an instance of the class, I honestly, don't see any reason in using Action<T> or delegate, as is I understood your question.
When I call methodA, I'd like to pass some sort of parameter so that
sometimes it just does MethodWork1 and sometimes it does both
MethodWork1 and MethodWork2.
Why do not just pass a simple parameter to MethodWorkA, like
public class DoWork()
{
public enum ExecutionSequence {CallMethod1, CallMethod2, CallBoth};
public MethodWorkA(List<long> TheList, ExecutionSequence exec)
{
if(exec == ExecutionSequence.CallMethod1)
MethodWork1(..);
else if(exec == ExecutionSequence.CallMethod2)
MethodWork2(..);
else if(exec == ExecutionSequence.Both)
{
MethodWork1(..);
MethodWork2(..);
}
}
public void MethodWork1(parameters) {}
public void MethodWork2(parameters) {}
}
Much simplier and understandable for your class consumer.
If this is not what you want, please explain.
EDIT
Just to give you an idea what you can do:
Example:
public class Executor {
public void MainMethod(long parameter, IEnumerable<Action> functionsToCall) {
foreach(Action action in functionsToCall) {
action();
}
}
}
and in the code
void Main()
{
Executor exec = new Executor();
exec.MainMethod(10, new List<Action>{()=>{Console.WriteLine("Method1");},
()=>{Console.WriteLine("Method2");}
});
}
The output will be
Method1
Method2
In this way you, for example, can push into the collection only functions you want to execute. Sure, in this case, the decision logic (which functions have to be executed) is determined outside of the call.

Categories

Resources