Don't know if it's possible on c# to have a callback that takes diferent arguments.
public void Woof(){
Console.WriteLine("woof");
}
public void Woof(System.Action callback){
Console.WriteLine("woof");
callback();
}
public void Foo(System.Action callback){
callback();
callback(()=> SomeOtherFunction());
}
public void TheCaller(){
Foo(Woof());
}
I know this code won't work, but is there a way to acomplish what I want?
No, single delegate can't have varying list of arguments.
Simple solution - make your callback to accept null/nullable for arguments that you don't have:
public void Foo(Action<Action> callbackWithOptionalArg)
{
callbackWithOptionalArg(null);
callbackWithOptionalArg(() => SomeOtherFunction());
}
Foo( optionalAction => optionalAction == null ? Woof() : Wool(optionalAction));
Alternative - have an interface with multiple methods as arguments:
interface IWoof
{
void Woof();
void Woof(System.Action callback)
}
public void Foo(IWoof dog)
{
dog.Woof();
dog.Woof(() => SomeOtherFunction());
}
class MyWoof : IWoof
{
public void Woof(){
Console.WriteLine("woof");
}
public void Woof(System.Action callback){
Console.WriteLine("woof with callback");
callback();
}
}
Foo(new MyWoof());
Related
I'm new to passing delegates and was wondering if the following code is possible to do?
CommandQueue.AddCommand(
new CommandItem(
group.MyGroupActionMovement(
new Vector3(-1000,-1000,-1000))));
ok to elaborate I'm going to do a code dump of my bad attempt at the command pattern...
So I'm trying to create a queue of commands. Starting with just the movement command. It takes a vector3 as a parameter. Other Commands will have different parameters like enums and game objects.
This is supposed to be my interface for commands/actions but, I've been messing with it to see what I can do.
public class IGroupAction: MonoBehaviour
{
public delegate bool Del(Vector3 destination);
public virtual bool Execute()
{
return true;
}
}
This is supposed to be the command/action unit/item
public class GroupActionItem
{
public IGroupAction MyGroupAction;
public GroupActionItem(IGroupAction.Del action)
{
}
public bool PerformAction()
{
return MyGroupAction.Execute();
}
}
This is the command pattern that I've completed so far
public class GroupAction
{
public List<GroupActionItem> Actions;
public GroupAction()
{
Actions = new List<GroupActionItem>();
}
public void AddAction(GroupActionItem groupActionItem)
{
Actions.Add(groupActionItem);
}
public void ClearActions()
{
Actions.Clear();
}
public void PerformActions()
{
if (Actions.Count >= 1)
{
if(Actions[0].PerformAction())
{
Actions.Remove(Actions[0]);
}
}
}
}
This is where I execute the movement command
public class GroupActionMovement : IGroupAction
{
public override bool Execute()
{
return Movement();
}
public bool Movement(Vector3 destination)
{
return true;
}
}
public class Group : MonoBehaviour
{
public GroupActionMovement MyGroupActionMovement;
}
This is the execution of the coded behavior.
public class Player : MonoBehaviour
{
public Dictionary<Group,GroupAction> PlayerGroupsActions;
public List<Group> Groups;
void Start()
{
PlayerGroupsActions = new Dictionary<Group, GroupAction>();
Groups = GetComponentsInChildren<Group>().ToList();
foreach (Group group in Groups)
{
GroupAction playerGroupActions = new GroupAction();
PlayerGroupsActions.Add(group,playerGroupActions);
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Alpha1))
{
//remove the foreach
foreach (Group group in Groups)
{
//directly apply the group
PlayerGroupsActions.TryGetValue(group, out GroupAction playerGroupActions);
if (playerGroupActions != null)
{
playerGroupActions.AddAction(new GroupActionItem(group.MyGroupActionMovement.Movement));
}
}
}
foreach (Group group in Groups)
{
PlayerGroupsActions.TryGetValue(group, out GroupAction playerFormationActions);
if (playerFormationActions != null)
{
if (playerFormationActions.Actions.Count != 0)
{
playerFormationActions.PerformActions();
}
}
}
}
}
I'm sorry if this isn't the best explanation of what is going on or, that a code dump is not the best way to explain what i'm doing.
don't pass it as a method, use something like this
CommandQueue.Command += doSomething;
void doSomething()
{
//doSomething
}
So that whenever the function CommandQueue.Command is run in the seperate class it will also run the doSomething() void in the main class
A delegate is not a method call, but the method it self, for the receiver to call it, whenever its needs to, with the parameters it wants.
Here is an example:
public delegate int MyDelegate(Vector3 vec);
public class MyCallingClass
{
public void DoSomething(MyDelegate method)
{
// Do something.
int result = method(new Vector3(-1000, -1000, -1000));
// Do something else.
}
}
public class MyClass
{
public static int MyStaticMethod(Vector3 arg)
{
// Do something with arg.
return x;
}
int MyMethod(Vector3 arg)
{
// Do something with arg.
return x;
}
private void DelegateWork()
{
MyCallingClass c = // Get an instance of MyCallingClass.
c.DoSomething(this.MyMethod);
c.DoSomething(MyClass.MyStaticMethod);
}
}
Multiple things to understand here:
At line c.DoSomething(this.MyMethod), the this is captured into the delegate you pass, meaning that when MyCallingClass.DoSomething will call the delegate, it will be called on the instance of MyClass. The line c.DoSomething(MyClass.MyStaticMethod) will call it with no instance, because it is a static method.
This is the method MyCallingClass.DoSomething that decides what parameters to pass, not the one that provides the delegate.
If you need the caller to provide arguments and the calling part to just decide when to call but not deciding what arguments to pass, then you can capture the argument ahead of time, and pass a delegate without argument, as follow.
public delegate int MyDelegate(); // No arguments anymore.
public class MyCallingClass
{
public void DoSomething(MyDelegate method)
{
// Do something.
int result = method(); // Not passing arguments anymore.
// Do something else.
}
}
public class MyClass
{
// ...
private void DelegateWork()
{
MyCallingClass c = // Get an instance of MyCallingClass.
c.DoSomething(() => this.MyMethod(new Vector3(-1000, -1000, -1000)));
c.DoSomething(() => MyClass.MyStaticMethod(new Vector3(-1000, -1000, -1000));
}
}
If you are not familiar with the syntax () => ..., this is a lambda expression, you can see it as an anonymous function created on-the-fly. It still respects the prototype returning an int and taking no parameters. The lambda expression now captures the construction of the Vector3 instance, and so this value will be used when the lambda will be called. A very important aspect to understand is that the values in the lambda expressions are evaluated when the lambda is called, not when it is created (lazy evaluation).
You do not have to use a specific delegate but instead you can use a Func<Vector3, int>, as follow:
// Not actually needed.
// public delegate int MyDelegate(Vector3 vec);
public class MyCallingClass
{
public void DoSomething(Func<Vector3, int> method)
{
...
}
}
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));
}
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.
class Test
{
public delegate void FruitDelegate(Fruit f);
public void Notify<T>(Action<T> del) where T : Fruit
{
FruitDelegate f = del; // Cannot implicitly convert type 'Action<T>' to 'FruitDelegate
}
}
Fruit is an empty class. Both of these delegates have the same signature.
I cannot seem to get any of this working. Maybe it would help if I explained what I am trying to do (provide some context).
I want to create a class that has a generic static method that provides a type and a method callback (like the above example).
The problem I am having is that the delegate contains a parameter and I don't want to have to cast it within the method callback. For example, I want this:
public void SomeMethod()
{
Test.Notify<Apple>(AppleHandler);
}
private void AppleHandler(Apple apple)
{
}
Instead of this:
public void SomeMethod()
{
Test.Notify<Apple>(AppleHandler);
}
private void AppleHandler(Fruit fruit)
{
Apple apple = (Apple)fruit;
}
Is this kind of thing possible?
is this what you want?
static void Main(string[] args)
{
Program p = new Program();
p.SomeMethod();
}
public class Fruit
{ }
public class Apple : Fruit { }
public delegate void FruitDelegate<in T>(T f) where T : Fruit;
class Test
{
public static void Notify<T>(FruitDelegate<T> del)
where T : Fruit, new()
{
T t = new T();
del.DynamicInvoke(t);
}
}
private void AppleHandler(Apple apple)
{
Console.WriteLine(apple.GetType().FullName);
}
public void SomeMethod()
{
FruitDelegate<Apple> del = new FruitDelegate<Apple>(AppleHandler);
Test.Notify<Apple>(del);
}
There is good reason you cannot do this. Suppose the rest of your method was:
class Test
{
public delegate void FruitDelegate(Fruit f);
public void Notify<T>(Action<T> del) where T : Fruit
{
FruitDelegate f = del;
f(new Banana()); //should be legal, but del may be Action<Apple>
}
}
That would definitely not work, so the compiler is correct here.
What about something like this?
public void Notify<T>(Action<T> del) where T : Fruit
{
FruitDelegate f = fruit => del((T)fruit);
}
The FruitDelegate instance, when invoked, would throw an InvalidCastException if, say, an AppleHandler was invoked with a Banana argument.
This question already has answers here:
Pass Method as Parameter using C#
(13 answers)
Closed 2 years ago.
I want to be able to pass a method as a parameter.
eg..
//really dodgy code
public void PassMeAMethod(string text, Method method)
{
DoSomething(text);
// call the method
//method1();
Foo();
}
public void methodA()
{
//Do stuff
}
public void methodB()
{
//Do stuff
}
public void Test()
{
PassMeAMethod("calling methodA", methodA)
PassMeAMethod("calling methodB", methodB)
}
How can I do this?
You need to use a delegate, which is a special class that represents a method. You can either define your own delegate or use one of the built in ones, but the signature of the delegate must match the method you want to pass.
Defining your own:
public delegate int MyDelegate(Object a);
This example matches a method that returns an integer and takes an object reference as a parameter.
In your example, both methodA and methodB take no parameters have return void, so we can use the built in Action delegate class.
Here is your example modified:
public void PassMeAMethod(string text, Action method)
{
DoSomething(text);
// call the method
method();
}
public void methodA()
{
//Do stuff
}
public void methodB()
{
//Do stuff
}
public void Test()
{
//Explicit
PassMeAMethod("calling methodA", new Action(methodA));
//Implicit
PassMeAMethod("calling methodB", methodB);
}
As you can see, you can either use the delegate type explicitly or implicitly, whichever suits you.
Use Action<T>
Example:
public void CallThis(Action x)
{
x();
}
CallThis(() => { /* code */ });
Or Func<>
Func<int, string> func1 = (x) => string.Format("string = {0}", x);
PassMeAMethod("text", func1);
public void PassMeAMethod(string text, Func<int, string> func1)
{
Console.WriteLine( func1.Invoke(5) );
}
Delegates are the language feature that you're going to need to use to accomplish what you're trying to do.
Here's an example using the code you have above (using the Action delegate as a shortcut):
//really dodgy code
public void PassMeAMethod(string text, Action method)
{
DoSomething(text);
method(); // call the method using the delegate
Foo();
}
public void methodA()
{
Console.WriteLine("Hello World!");
}
public void methodB()
{
Console.WriteLine("42!");
}
public void Test()
{
PassMeAMethod("calling methodA", methodA)
PassMeAMethod("calling methodB", methodB)
}
Building on what BrunoLM did, as that example was brief.
//really dodgy code
public void PassMeAMethod(string text, Action method)
{
DoSomething(text);
method();
Foo();
}
// Elsewhere...
public static void Main(string[] args)
{
PassMeAMethod("foo", () =>
{
// Method definition here.
}
);
// Or, if you have an existing method in your class, I believe this will work
PassMeAMethod("bar", this.SomeMethodWithNoParams);
}
c# .net2.0 - Let me show a detailed answer for the topic (pass-a-method-as-a-parameter).
In my scenario i'm configuring a set of System.Timers.Timer-s, each with a different _Tick method.
delegate void MyAction();
// members
Timer tmr1, tmr2, tmr3;
int tmr1_interval = 4.2,
tmr2_interval = 3.5;
tmr3_interval = 1;
// ctor
public MyClass()
{
..
ConfigTimer(tmr1, tmr1_interval, this.Tmr_Tick);
ConfigTimer(tmr2, tmr2_interval, (sndr,ev) => { SecondTimer_Tick(sndr,ev); });
ConfigTimer(tmr3, tmr3_interval, new MyAction((sndr,ev) => { Tmr_Tick((sndr,ev); }));
..
}
private void ConfigTimer(Timer _tmr, int _interval, MyAction mymethod)
{
_tmr = new Timer() { Interval = _interval * 1000 };
// lambda to 'ElapsedEventHandler' Tick
_tmr.Elpased += (sndr, ev) => { mymethod(sndr, ev); };
_tmr.Start();
}
private void Tmr_Tick(object sender, ElapsedEventArgs e)
{
// cast the sender timer
((Timer)sender).Stop();
/* do your stuff here */
((Timer)sender).Start();
}
// Another tick method
private void SecondTimer_Tick(object sender, ElapsedEventArgs e) {..}