Trying to send an UnityAction as a parameter for one of my methods, like so:
public void PopulateConversationList(string [] fullConversation, string onLastPagePrompt, string npcName, int stage, UnityAction action)
{
conversations.Add(new Conversation(fullConversation, onLastPagePrompt, npcName, stage, action));
}
dialogHolder.PopulateConversationList(stage1, "Okay", _name, 1, QuestManager.Instance().ActivateQuest);
this works fine, but now I want to pass the following Action as a parameter:
public void ActivateQuest(int questId)
{
Debug.Log("This is the id: " + questId);
}
However, it will not work when I use an action that has a parameter:
dialogHolder.PopulateConversationList(stage1, "Okay", _name, 1, QuestManager.Instance().ActivateQuest(2));
The above gives error: Cannot convert from void to UnityAction.
How can I pass a UnityAction with a parameter, as a parameter?
I call the Action in the conversation like this:
dialog.OnAccept(ConvList[i].onLastPagePrompt, () =>
{
ConvList[i].action();
dialog.Hide();
});
EDIT: The solution I ended up going with:
enter dialogHolder.PopulateConversationList(stage1, "Okay", _name, 1, () =>
{
QuestManager.Instance().ActivateQuest(0);
});
This way I can call several methods as well.
Here is the problem:
public void PopulateConversationList(string[] fullConversation, string onLastPagePrompt, string npcName, int stage, UnityAction action)
The action argument does not accept any parameter but you are passing it a function that requires a parameter:
public void ActivateQuest(int questId)
{
Debug.Log("This is the id: " + questId);
}
with:
dialogHolder.PopulateConversationList(stage1, "Okay", _name, 1, QuestManager.Instance().ActivateQuest(2));
Notice the 2 passed to the ActivateQuest function.
Passing parameter to UnityEvent is not really that simple as one would expect. You must derive from UnityEvent and also provide the type of parameter. In this case you want to pass int. You must create a class that derives from UnityEvent with int as generic.
public class IntUnityEvent : UnityEvent<int>{}
The IntUnityEvent action variable can then be passed around as parameter in your functions instead of UnityAction action.
Below is a simplified and generic solution provided so that it will be helpful to others too. Just add your other parameters to the PopulateConversationList function and you should be good to go. It's well commented.
[System.Serializable]
public class IntUnityEvent : UnityEvent<int>
{
public int intParam;
}
public IntUnityEvent uIntEvent;
void Start()
{
//Create the parameter to pass to the function
if (uIntEvent == null)
uIntEvent = new IntUnityEvent();
//Add the function to call
uIntEvent.AddListener(ActivateQuest);
//Set the parameter value to use
uIntEvent.intParam = 2;
//Pass the IntUnityEvent/UnityAction to a function
PopulateConversationList(uIntEvent);
}
public void PopulateConversationList(IntUnityEvent action)
{
//Test/Call the function
action.Invoke(action.intParam);
}
//The function to call
public void ActivateQuest(int questId)
{
Debug.Log("This is the id: " + questId);
}
Note:
If possible, avoid using UnityEvent in Unity. Use use C# Action and delegate since they are more easier to use. Also, they are much more faster than Unity's UnityEvent.
you could use something like this
public void RegisterEvent<T, U, V>(object eventName, Action<T, U, V> handler)
{
Register(eventName, handler);
}
This should work
private void Awake()
{
UnityAction unityAction = null;
unityAction += () => Jamen1("UnityAction Jamen1");
unityAction += Jamen2;
unityAction += () =>
{
print("UnityAction Jamen3");
};
Jamen3(unityAction)
}
void Jamen1(string text)
{
print(text);
}
void Jamen2()
{
print("UnityAction Jamen2");
}
void Jamen3(UnityAction unityAction)
{
unityAction?.Invoke();
}
Note: the ? is a null check.
// Null Check
unityAction?.Invoke();
// Don't Null Check
unityAction.Invoke();
I use lambda expression to solve this problem
dialogHolder.PopulateConversationList(stage1, "Okay", _name, 1, () => {
QuestManager.Instance().ActivateQuest(2);
});
So, everyone here fails to address the less than, greater than operator on the UnityAction.
It seems like you're well versed with the void UnityAction
public void CallAction(UnityAction action){
action?.invoke();
}
But, say you want to pass a float.
public void SendFloat(UnityAction<float> action){
action?.invoke(5.0f);
}
Or, if you want to pass a float and another action
public void SendFloatAndAction(UnityAction<float, UnityAction> action){
action?.invoke(5.0f, ()=>
{
Debug.Log("Called");
});
}
Pretty much, you can put whatever information that you want into the less than, greater than operator of the UnityAction to allow that to be passed as a parameter.
As stated in the Unity documentation, a UnityAction or Delegate that does not have an action assigned to it is null and attempting to invoke it will throw an error. Instead of adding an extra 2-3 lines for a null check, you can add a question mark (?) which will only invoke the UnityAction or Delegate if it is not null.
Unfortunately, the docs are inadequate to please my tastes after looking at the nicer React docs but here is the Unity Learn tutorial on delegates: https://learn.unity.com/tutorial/delegates
And here are the docs for UnityAction although they do not do the type justice.
https://docs.unity3d.com/ScriptReference/Events.UnityAction.html
https://docs.unity3d.com/ScriptReference/Events.UnityAction_4.html
If you want to use UnityAction, you must use UnityEngine.Events by adding the line using UnityEngine.Events; to the top of your script.
One last note, I have not experimented much with UnityAction calls but I believe that you are only allowed to set between 0 and 4 parameters.
Related
I have several methods all with the same parameter types and return values but different names and blocks. I want to pass the name of the method to run to another method that will invoke the passed method.
public int Method1(string)
{
// Do something
return myInt;
}
public int Method2(string)
{
// Do something different
return myInt;
}
public bool RunTheMethod([Method Name passed in here] myMethodName)
{
// Do stuff
int i = myMethodName("My String");
// Do more stuff
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
This code does not work but this is what I am trying to do. What I don't understand is how to write the RunTheMethod code since I need to define the parameter.
You can use the Func delegate in .NET 3.5 as the parameter in your RunTheMethod method. The Func delegate allows you to specify a method that takes a number of parameters of a specific type and returns a single argument of a specific type. Here is an example that should work:
public class Class1
{
public int Method1(string input)
{
//... do something
return 0;
}
public int Method2(string input)
{
//... do something different
return 1;
}
public bool RunTheMethod(Func<string, int> myMethodName)
{
//... do stuff
int i = myMethodName("My String");
//... do more stuff
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
}
You need to use a delegate. In this case all your methods take a string parameter and return an int - this is most simply represented by the Func<string, int> delegate1. So your code can become correct with as simple a change as this:
public bool RunTheMethod(Func<string, int> myMethodName)
{
// ... do stuff
int i = myMethodName("My String");
// ... do more stuff
return true;
}
Delegates have a lot more power than this, admittedly. For example, with C# you can create a delegate from a lambda expression, so you could invoke your method this way:
RunTheMethod(x => x.Length);
That will create an anonymous function like this:
// The <> in the name make it "unspeakable" - you can't refer to this method directly
// in your own code.
private static int <>_HiddenMethod_<>(string x)
{
return x.Length;
}
and then pass that delegate to the RunTheMethod method.
You can use delegates for event subscriptions, asynchronous execution, callbacks - all kinds of things. It's well worth reading up on them, particularly if you want to use LINQ. I have an article which is mostly about the differences between delegates and events, but you may find it useful anyway.
1 This is just based on the generic Func<T, TResult> delegate type in the framework; you could easily declare your own:
public delegate int MyDelegateType(string value)
and then make the parameter be of type MyDelegateType instead.
From OP's example:
public static int Method1(string mystring)
{
return 1;
}
public static int Method2(string mystring)
{
return 2;
}
You can try Action Delegate! And then call your method using
public bool RunTheMethod(Action myMethodName)
{
myMethodName(); // note: the return value got discarded
return true;
}
RunTheMethod(() => Method1("MyString1"));
Or
public static object InvokeMethod(Delegate method, params object[] args)
{
return method.DynamicInvoke(args);
}
Then simply call method
Console.WriteLine(InvokeMethod(new Func<string,int>(Method1), "MyString1"));
Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));
In order to provide a clear and complete answer, I'm going to start from the very beginning before showing three possible solutions.
A brief introduction
All .NET languages (such as C#, F#, and Visual Basic) run on top of the Common Language Runtime (CLR), which is a VM that runs code in the Common Intermediate Language (CIL), which is way higher level than machine code. It follows that methods aren't Assembly subroutines, nor are they values, unlike functional languages and JavaScript; rather, they're symbols that CLR recognizes. Not being values, they cannot be passed as a parameter. That's why there's a special tool in .NET. That is, delegates.
What's a delegate?
A delegate represents a handle to a method (the term handle is to be preferred over pointer as the latter would be an implementation detail). Since a method is not a value, there has to be a special class in .NET, namely Delegate, which wraps up any method. What makes it special is that, like very few classes, it needs to be implemented by the CLR itself and couldn't be simply written as a class in a .NET language.
Three different solutions, the same underlying concept
The type–unsafe way
Using the Delegate special class directly.
Example:
static void MyMethod()
{
Console.WriteLine("I was called by the Delegate special class!");
}
static void CallAnyMethod(Delegate yourMethod)
{
yourMethod.DynamicInvoke(new object[] { /*Array of arguments to pass*/ });
}
static void Main()
{
CallAnyMethod(MyMethod);
}
The drawback here is your code being type–unsafe, allowing arguments to be passed dynamically, with no constraints.
The custom way
Besides the Delegate special class, the concept of delegates spreads to custom delegates, which are declarations of methods preceded by the delegate keyword. They are type–checked the same way as “normal” method invocations, making for type-safe code.
Example:
delegate void PrintDelegate(string prompt);
static void PrintSomewhere(PrintDelegate print, string prompt)
{
print(prompt);
}
static void PrintOnConsole(string prompt)
{
Console.WriteLine(prompt);
}
static void PrintOnScreen(string prompt)
{
MessageBox.Show(prompt);
}
static void Main()
{
PrintSomewhere(PrintOnConsole, "Press a key to get a message");
Console.Read();
PrintSomewhere(PrintOnScreen, "Hello world");
}
The standard library's way
Alternatively, you can stick with a delegate that's part of the .NET Standard:
Action wraps up a parameterless void method;
Action<T1> wraps up a void method with one parameter of type T1;
Action<T1, T2> wraps up a void method with two parameters of types T1 and T2, respectively,
and so forth;
Func<TR> wraps up a parameterless function with TR return type;
Func<T1, TR> wraps up a function with TR return type and with one parameter of type T1;
Func<T1, T2, TR> wraps up a function with TR return type and with two parameters of types T1 and T2, respectively;
and so forth.
However, bear in mind that by using predefined delegates like these, parameter names won't be self-describing, nor is the name of the delegate type meaningful as to what instances are supposed to do. Therefore, refrain from using them in contexts where their purpose is not absolutely self-evident.
The latter solution is the one most people posted. I'm also mentioning it in my answer for the sake of completeness.
The solution involves Delegates, which are used to store methods to call. Define a method taking a delegate as an argument,
public static T Runner<T>(Func<T> funcToRun)
{
// Do stuff before running function as normal
return funcToRun();
}
Then pass the delegate on the call site:
var returnValue = Runner(() => GetUser(99));
You should use a Func<string, int> delegate, that represents a function taking a string argument and returning an int value:
public bool RunTheMethod(Func<string, int> myMethod)
{
// Do stuff
myMethod.Invoke("My String");
// Do stuff
return true;
}
Then invoke it this way:
public bool Test()
{
return RunTheMethod(Method1);
}
While the accepted answer is absolutely correct, I would like to provide an additional method.
I ended up here after doing my own searching for a solution to a similar question.
I am building a plugin driven framework, and as part of it I wanted people to be able to add menu items to the applications menu to a generic list without exposing an actual Menu object because the framework may deploy on other platforms that don't have Menu UI objects. Adding general info about the menu is easy enough, but allowing the plugin developer enough liberty to create the callback for when the menu is clicked was proving to be a pain. Until it dawned on me that I was trying to re-invent the wheel and normal menus call and trigger the callback from events!
So the solution, as simple as it sounds once you realize it, eluded me until now.
Just create separate classes for each of your current methods, inherited from a base if you must, and just add an event handler to each.
Here is an example Which can help you better to understand how to pass a function as a parameter.
Suppose you have Parent page and you want to open a child popup window. In the parent page there is a textbox that should be filled basing on child popup textbox.
Here you need to create a delegate.
Parent.cs
// declaration of delegates
public delegate void FillName(String FirstName);
Now create a function which will fill your textbox and function should map delegates
//parameters
public void Getname(String ThisName)
{
txtname.Text=ThisName;
}
Now on button click you need to open a Child popup window.
private void button1_Click(object sender, RoutedEventArgs e)
{
ChildPopUp p = new ChildPopUp (Getname) //pass function name in its constructor
p.Show();
}
IN ChildPopUp constructor you need to create parameter of 'delegate type' of parent //page
ChildPopUp.cs
public Parent.FillName obj;
public PopUp(Parent.FillName objTMP)//parameter as deligate type
{
obj = objTMP;
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
obj(txtFirstName.Text);
// Getname() function will call automatically here
this.DialogResult = true;
}
If you want to pass Method as parameter, use:
using System;
public void Method1()
{
CallingMethod(CalledMethod);
}
public void CallingMethod(Action method)
{
method(); // This will call the method that has been passed as parameter
}
public void CalledMethod()
{
Console.WriteLine("This method is called by passing it as a parameter");
}
If the method passed needs to take one argument and return a value, Func is the best way to go. Here is an example.
public int Method1(string)
{
// Do something
return 6;
}
public int Method2(string)
{
// Do something different
return 5;
}
public bool RunTheMethod(Func<string, int> myMethodName)
{
// Do stuff
int i = myMethodName("My String");
Console.WriteLine(i); // This is just in place of the "Do more stuff"
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
Read the docs here
However, if your method that is passed as a parameter does not return anything, you can also use Action. It supports up to 16 paramaters for the passed method. Here is an example.
public int MethodToBeCalled(string name, int age)
{
Console.WriteLine(name + "'s age is" + age);
}
public bool RunTheMethod(Action<string, int> myMethodName)
{
// Do stuff
myMethodName("bob", 32); // Expected output: "bob's age is 32"
return true;
}
public bool Test()
{
return RunTheMethod(MethodToBeCalled);
}
Read the documentation here
Here is an example without a parameter:
http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string
with params:
http://www.daniweb.com/forums/thread98148.html#
you basically pass in an array of objects along with name of method. you then use both with the Invoke method.
params Object[] parameters
class PersonDB
{
string[] list = { "John", "Sam", "Dave" };
public void Process(ProcessPersonDelegate f)
{
foreach(string s in list) f(s);
}
}
The second class is Client, which will use the storage class. It has a Main method that creates an instance of PersonDB, and it calls that object’s Process method with a method that is defined in the Client class.
class Client
{
static void Main()
{
PersonDB p = new PersonDB();
p.Process(PrintName);
}
static void PrintName(string name)
{
System.Console.WriteLine(name);
}
}
I don't know who might need this, but in case you're unsure how to send a lambda with a delegate, when the function using the delegate doesn't need to insert any params in there you just need the return value.
SO you can also do this:
public int DoStuff(string stuff)
{
Console.WriteLine(stuff);
}
public static bool MethodWithDelegate(Func<int> delegate)
{
///do stuff
int i = delegate();
return i!=0;
}
public static void Main(String[] args)
{
var answer = MethodWithDelegate(()=> DoStuff("On This random string that the MethodWithDelegate doesn't know about."));
}
I have a method which accepts an Action delegate and executes the given method as shown here:
public void ExpMethod(Action inputDel)
{
inpuDel();
}
I can call above given method like this:
ExpMethod(() => {/*do something that matters*/});
Everything works fine. So far so good. Now I want to have a method which takes a generic Action delegate as an input parameter - like this:
public void ExpGenMethod(Action<string,int> inputDel)
{
// I don't know how to call the supplied delegate as it requires parameters
}
Also, I am trying to call this ExpGenMethod in this way:
ExpGenMethod(("Hi",1) => {/*do something that makes sense*/});
But it shows syntax errors. Please let me know how to use generic action delegate in this case?
The whole point of a delegate is to have a pointer to a method. Passing parameters to it while it´s being declared is therefor pointless. Instead pass the arguments for your delegate within the method that executes the delegate, in your case within ExpGenMethod:
You should do this instead:
public void ExpGenMethod(Action<string,int> inputDel)
{
inputDel("Hi", 1);
}
And call it like this:
ExpGenMethod((x, y) => {/*do something that makes sense*/});
When executing that delegate x evaluates to "Hi" and y to 1.
Typically, you'll want the heavy lifting to happen in the ExpGenMethod and in the delegate itself you'll simply be passing the parameters to the ExpGenMethod.
using System;
public class Program
{
public static void Main()
{
ExpGenMethod((options) =>
{
options.x = "Hi";
options.y = 1;
});
}
public static void ExpGenMethod(Action<Options> inputDel)
{
var options = new Options();
inputDel(options);
/* have access to x and y so do some thing useful with these values */
Console.WriteLine(options.x);
Console.WriteLine(options.y);
}
}
public class Options
{
public string x { set; get;}
public int y { set; get; }
}
(a,b) => {/*do something that matters*/} means that a and b are parameters which are going to be specified during the call. Here you are using constant so you should do something like () => { use "Hi"; use 1;} and that would get you back to your first working example.
If you want to pass parameter you cna do it this way:
public void work()
{
ExpGenMethod((a) => {/*do something that matters*/});
}
public void ExpGenMethod(Action<int> inputDel, int parameterToUse)
{
inputDel(parameterToUse);
}
As a follow on to what #HimBromBeere explained:
The keyword Action is defined as delegate:
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
So if the method is defined as:
public void ExpGenMethod(Action<string,int> inputDel)
{
inputDel("Hi", 1);
}
You can call ExpGenMethod with parameters x,y is using a Lambda expression, and see the results using Console.Writeline as follows:
ExpGenMethod((x, y) => { Console.WriteLine($"{x} {y}"); });
I have this class where I define one or more functions that I want to pass as delegates:
class Sports
{
public string judo(Player player, Venue venue)
{
//function body
}
}
Here is a class with a method that can accept one of these functions as a delegate:
public class Player
{
public void play(Venue venue,Func<Player,Venue,string> tournament)
{
string result = tournament(this,venue);
//do something with result
}
}
And here is a call to that method that passes in a suitable function:
public void playJudo(Player player,Venue venue)
{
Sports sports=new Sports();
player.play(venue,sports.judo(player,venue));
}
This doesn't compile; VS reports that the call to player.play() has invalid arguments. I don't understand this--judo() returns a string, and the header for play() defines it as accepting a function that returns a string. What's wrong here?
When you're using delegates in a parameter like Func<T1, T2, T3> there, you actually want to pass the function as the parameter, not the results of the function. Applying the function call operator, parens, calls the function. Try something like:
public void playJudo(Player player, Venue venue)
{
Sports sports = new Sports();
player.play(venue, sports.judo);
}
You are passing a the return value of sports.judo which is a string. Make public string judo(Player player, Venue venue) a static method or pass just sports.judo
I use a thread to execute some process on a machine. Eventually, the progress is reported back in an other thread. To update the GUI with the status of the process, I use a delegate like this:
public delegate void UpdateProgressDelegate(string description, int scriptnumber);
public void UpdateProgress(string description, int scriptnumber) {
if (treeView.InvokeRequired) {
treeView.Invoke(new UpdateProgressDelegate(UpdateProgress), description, scriptnumber);
return;
}
// Update the treeview
}
And to call this delegate I use:
form.UpdateProgress("Ready", 3);
When the Invoke is called, I get a TargetParameterCountException: Parameter count mismatch.
I thought I could fix this by placing the string and int parameters in a single object like this:
public delegate void UpdateProgressDelegate(object[] updateinfo);
public void UpdateProgress(object[] updateinfo) {
string description = (string) updateinfo[0];
int scriptnumber = (int) updateinfo[1];
if (treeView.InvokeRequired) {
treeView.Invoke(new UpdateProgressDelegate(UpdateProgress), new object[] { description, scriptnumber });
return;
}
// Update the treeview
}
And to call it I use:
form.UpdateProgress(new object[] {"Ready", 3});
But this doesn't work either. I keep getting the same TargetParameterCountException. Any ideas how I could fix this? Thanks in advance!
I would say: do it the easy way:
treeView.Invoke((MethodInvoker)delegate {
UpdateProgress(description, scriptnumber);
});
or (equally):
treeView.Invoke((MethodInvoker) () => UpdateProgress(description, scriptnumber));
This gives you static-checking at the compiler, and IIRC MethodInvoker is checked explicitly, and called with Invoke() rather than DynamicInvoke(), making it faster too.
Re why it doesn't work; in your example with:
public delegate void UpdateProgressDelegate(object[] updateinfo);
you are actually passing two parameters; to disambiguate and pass a single array to a params here, you need to double-wrap it:
treeView.Invoke(new UpdateProgressDelegate(UpdateProgress),
new object[] { new object[] {description, scriptnumber }});
Basically, the outer array is the "array of all the parameters", which contains a single element, which is the array that we wan't to pass as the first parameter (updateinfo).
This should work:
public delegate void UpdateProgressDelegate(string description, int scriptnumber);
public void UpdateProgress(string description, int scriptnumber) {
if (treeView.InvokeRequired) {
treeView.Invoke(new UpdateProgressDelegate(UpdateProgress), new object[] { description, scriptnumber });
return;
}
// Update the treeview
}
I want to have a library that will have a function in it that accepts an object for it's parameter.
With this object I want to be able to call a specified function when X is finished. The function that will be called is to be specified by the caller, and X will be done and monitored by the library.
How can I do this?
For reference I'm using C# and .NET 3.5
Two options for you:
Have the function accept a delegate (Action for a callback that doesn't return anything, Func for one that does) and use an anonymous delegate or Lambda Expression when calling it.
Use an interface
Using a delegate/lambda
public static void DoWork(Action processAction)
{
// do work
if (processAction != null)
processAction();
}
public static void Main()
{
// using anonymous delegate
DoWork(delegate() { Console.WriteLine("Completed"); });
// using Lambda
DoWork(() => Console.WriteLine("Completed"));
}
If your callback needs to have something passed to it, you can use a type parameter on Action:
public static void DoWork(Action<string> processAction)
{
// do work
if (processAction != null)
processAction("this is the string");
}
public static void Main()
{
// using anonymous delegate
DoWork(delegate(string str) { Console.WriteLine(str); });
// using Lambda
DoWork((str) => Console.WriteLine(str));
}
If it needs multiple arguments, you can add more type parameters to Action. If you need a return type, as mentioned use Func and make the return type the last type parameter (Func<string, int> is a function accepting a string and returning an int.)
More about delegates here.
Using an interface
public interface IObjectWithX
{
void X();
}
public class MyObjectWithX : IObjectWithX
{
public void X()
{
// do something
}
}
public class ActionClass
{
public static void DoWork(IObjectWithX handlerObject)
{
// do work
handlerObject.X();
}
}
public static void Main()
{
var obj = new MyObjectWithX()
ActionClass.DoWork(obj);
}
Sounds like a perfect recipe for delegates - in particular, callbacks with delegates are exactly how this is handled in the asynchronous pattern in .NET.
The caller would usually pass you some state and a delegate, and you store both of them in whatever context you've got, then call the delegate passing it the state and whatever result you might have.
You could either make the state just object or potentially use a generic delegate and take state of the appropriate type, e.g.
public delegate void Callback<T>(T state, OperationResult result)
Then:
public void DoSomeOperation(int otherParameterForWhateverReason,
Callback<T> callback, T state)
As you're using .NET 3.5 you might want to use the existing Func<...> and Action<...>
delegate types, but you may find it makes it clearer to declare your own. (The name may make it clearer what you're using it for.)
The object in question will need to implement an interface provided by you. Take the interface as a parameter, and then you can call any method that the interface exposes. Otherwise you have no way of knowing what the object is capable of. That, or you could take a delegate as a parameter and call that.
Is there a reason not to have your library provide a public event to be fired when the operation is complete? Then the caller could just register to handle the event and you don't have to worry about passing around objects or delegates.
The object implementing an interface you have provided would work, but it seems to be more the Java approach than the .NET approach. Events seem a bit cleaner to me.
You can use System.Action available in C#.NET for callback functions. Please check this sample example:
//Say you are calling some FUNC1 that has the tight while loop and you need to
//get updates on what percentage the updates have been done.
private void ExecuteUpdates()
{
Func1(Info => { lblUpdInfo.Text = Info; });
}
//Now Func1 would keep calling back the Action specified in the argument
//This System.Action can be returned for any type by passing the Type as the template.
//This example is returning string.
private void Func1(System.Action<string> UpdateInfo)
{
int nCount = 0;
while (nCount < 100)
{
nCount++;
if (UpdateInfo != null) UpdateInfo("Counter: " + nCount.ToString());
//System.Threading.Thread.Sleep(1000);
}
}