Delegates with methods that have different number of parameters - c#

I've run into a problem. I have something like that:
public class ListSorter : MonoBehaviour
{
public delegate void MyDelegate();
public static MyDelegate myDelegate;
void Start ()
{
ListSorter.myDelegate += A(5);// <-- here I know i cant do it
ListSorter.myDelegate += B;
myDelegate(); //<-- how to call 2 different function with one delegate?
}
public void A(int iVar)
{
print(iVar);
}
public void B()
{
///...
}
}
So as you see, I already know where and how many of parameters I want to have. The question is how to call those function A and B while function A has a parameter and B doesn't have one?

Wrap the function call in an anonymous delegate that matches the target type (no parameters, no return value):
ListSorter.myDelegate += (() => A(5));
ListSorter.myDelegate += B;

To call A with a fixed parameter you need to create a new method that matches the delegate's signature, namely having no parameters and no return value, who's body calls A, passing 5. You could do this with a new named method, or you could use an anonymous method; both would work fine:
ListSorter.myDelegate += () => A(5);
Other than that, you're properly creating a delegate that calls two methods, so invoking it will invoke both of the method's you've added to it.

Related

Passing a parameter to a delegate during creation and maybe use it like std::placeholders [duplicate]

This question already has answers here:
Pass extra parameters to an event handler?
(10 answers)
Pass extra parameter to C# callback
(2 answers)
How to pass a delegate with different number of arguments than originally designed
(2 answers)
Closed 3 years ago.
I am currently reading up on delegates and I wanted to know if there was a way to create a delegate and pass parameters to that delegate during creation.
suppose I have this method
public void test(int a,int b);
Now I can do this
public delegate void DelegateWithParameter(int a,int b);
DelegateWithParameter d = new DelegateWithParameter(test);
d(1,2); //Works
Now how can I create a delegate that has parameters embedded in it so I can simply do this d();?
Also can I pass in partial parameters ? Like pass in second parameter during delegate creation and then pass the first parameter during the use ? I know in C++ we use std::placeholders. I wonder if C# has something like that ?
Well, if your delegates param-list is that static and you allways provide the same values anyway, why do you even have one? So just use this:
public delegate void DelegateWithParameter();
DelegateWithParameter d = new DelegateWithParameter(() => test(2, 1));
d(); //Works
Basically a delegate is a function signature.
public delegate void DelegateWithParameters(int a, int b);
Your delegate has a signature of a function that accepts 2 ints as parameters and returns void. In order to call a delegate of that type, you have to use two int parameters.
However, you could wrap that delegate in another method, so that you don't have to provide the parameters. Let's say I want to call a delegate above with a default set of parameters.
Now I could call that function from anywhere, without specifying parameters for the delegate. (Although they will always be necessary)
public void CallDelegate(DelegateWithParameters method)
{
method(1, 2);
}
public void Test(int a,int b)
{
// Do something
}
// Use it like so
CallDelegate(Test);
Or you could have a class with a field containing the delegate for example:
class DelegateInvoker
{
private DelegateWithParameters method;
public DelegateInvoker(DelegateWithParameters method)
{
this.method = method ?? throw new ArgumentNullException(nameof(method));
}
// Note this signature is parameterless
public void InvokeDelegate()
{
// but you do call the delegate with the required parameters
this.method(1, 2);
}
}
// Then call it like this
var delegateInvoker = new DelegateInvoker(Test);
delegateInvoker.InvokeDelegate();
A more inline approach would be to create a function on the fly, but it is basically the same thing. You define a new function to wrap the delegate.
DelegateWithParameters method = Test;
// define a new, parameterless method to wrap the delegate
var delegateInvoker = () => method(1, 2);
delegateInvoker();
Lastly, note that the newly created function actually has another signature. So you could define our new function as a delegate like this:
delegate void ParameterlessDelegate();
And the last example could become:
DelegateWithParameters method = Test;
// define a new, parameterless method to wrap the delegate
ParameterlessDelegate delegateInvoker = () => method(1, 2);
delegateInvoker();

Passing argument to an Action without using an anonymous function?

Is there a way I can pass through an argument to an Action without using an anonymous function?
Eg, the following code works fine:
private void doSomethingAndLogIt(string log, Action dosomething)
{
Debug.WriteLine(log);
dosomething();
}
private void multiplyIt()
{
_result = "great";
}
...
doSomethingAndLogIt("Did something", multiplyIt);
but what I want to do is this:
private void doSomethingAndLogIt(string log, Action<int> dosomething)
{
Debug.WriteLine(log);
dosomething(???);
}
private void multiplyIt(int a)
{
_result = "great";
}
doSomethingAndLogIt("Did something", multiplyIt(5));
I realise that I can do this:
private void doSomethingAndLogIt(string log, Action<int> dosomething, int inputValue)
{
Debug.WriteLine(log);
dosomething(inputValue);
}
private void multiplyIt(int a)
{
_result = "great";
}
doSomethingAndLogIt("Did something", multiplyIt, 5);
but it's pretty confusing. I also realise that I can do this:
doSomethingAndLogIt("Did something", () => {
multiplyIt(5);
});
but it would be great if I could do this:
doSomethingAndLogIt("Did something", multiplyIt(5));
You do not need to do anything special. This code below:
doSomethingAndLogIt("Test", () => multiplyIt(5));
will already do what you are after. When the delegate is called, the parameter 5 will be passed in as well. Why? Because the callee will call your delegate, and you will call the method multiply with the argument 5.
Here is a quick test.
It isn't possible to do that as of the current version of C#, here's why...
Let's take your example (fake syntax)
public int MultiplyIt(int value)
{
//Do something that has side-effects
}
public void SomeMethod(Action<int> someAction<int>)
{
//Do something
someAction();
}
Now let's create an override of that method:
public void SomeMethod(int someValue)
{
//Do something
}
Now you call it:
SomeMethod(multiplyIt(5))
Which one does the compiler call?
Lets say you don't overload it (or that for some reason the compiler shouts an error if you do, but it is legal).
What then is the difference between these two calls?
SomeMethod(multiplyIt(5));
SomeMethod(() => multiplyIt(5));
Technically the first one runs multiplyIt before passing its value to SomeMethod. The second one multiplyIt may never be called, or it may alter something and then call it. That is an important distinction. If you add in some method to call it without the () => part, the developer can't know, without reading documentation, how the method call (and the action) are called. Is it a normal method call? The "special" delegate case? Who knows.
The () => isn't that much of a price to pay to be able to read a method and understand that you are passing in a delegate vs a value.

Does C# have a concept of methods inside of methods?

I have been using javascript and I made a lot of use of functions inside of functions. I tried this in C# but it seems they don't exist. If I have the following:
public abc() {
}
How can I code a method d() that can only be called
from inside the method the method abc() ?
I wouldn't worry so much about the restriction of access to a method on the method level but more class level, you can use private to restrict access of the method to that specific class.
Another alternative would be to use lambdas/anonymous methods, or if you're using C# 4.0, Action/Tasks to create them inside your method.
An example of an anonymous method using a delegate (C# 1/2/3/4) for your specific example (incl. I need an action that can take a string parameter and return a string?) would be something like this:
delegate string MyDelegate(string);
public void abc() {
// Your code..
MyDelegate d = delegate(string a) { return a + "whatever"; };
var str = d("hello");
}
.. using C# 3/4:
public void abc() {
// Your code..
Func<string, string> d = (a) => { return a + "whatever"; };
var str = d("hello");
}
.. using a more ideal solution through private method:
private string d(string a)
{
return a + "whatever";
}
public void abc()
{
// Your code..
var str = d("hello");
}
Based on your comment for another answer: I would just like to have this at the bottom of the method and then call it from some earlier code.
This won't be possible, you would need to define a variable for your method using either delegates or Actions and so it would need to be fully initialised by time you call it. You wouldn't then be able to define this at the bottom of your method. A much better option would be to simply create a new private method on your class and call that.
It is not the way to define classes, but you could do:
public abc() {
Action d = () => {
// define your method
};
d();
}
You cannot declare a method inside another method, but you can create anonymous functions inside methods:
public void abc()
{
Action d = () => { ... };
// ...
d();
}
... that can only be called from inside the method the method abc() ?
The method can only be called if you have a reference to it. If you don't store the reference elsewhere then you should be fine.
how can I pass and return a string to the action?
Use a Func instead of an Action:
Func<string, string> d = s => {
return s + "foo";
};
The reason I would like to do this is to make my code more readable.
It's good to try to make your code more readable but I think this change will make it less readable. I suggest you use ordinary methods, and not anonymous functions. You can make them private so that they cannot be called from outside your class.
Use action delegates. More effective than you did.
public abc() {
Action <int> GetInt = (i) =>
{
//Write code here
Console.Writeline("Your integer is: {0}", i);
};
GetInt(10);
}
Action is a delegate so you can give parameter as a method, not variable. Action delegate encapsulates a method that has no parameters and does not return a value. Check it from MSDN.
Yes, they are called delegates and anonymous methods.
Delegate signatures must be predefined outside of the method for the body to be assigned, so it's not exactly like a function. You would first declare a delegate:
class MyClass {
public delegate boolean Decider(string message);
/* ... */
}
And then in MyClass.MyMethod you can say Decider IsAllLowerCase = /* method name or anonymous method */; and then use it with var result = IsAllLowerCase(s);.
The good news is that .NET already has delegate definitions for most signatures you could possibly need. System.Action has assorted signatures for methods which do not return anything, and System.Func is for the ones that do.
As shown elsewhere,
Action<int, string> a = (n, s) => { for(var i=0; i<n; i++) Console.WriteLine(s);};
Allows you to call a( /* inputs */ ); as if it was a local variable. (stuff) => { code } is "lambda expression" or an anonymous method, you can also just pass a name of a method (if the signature matches):
Action<string> a = Console.WriteLine;
If you want to return something, use Func:
Func<bool, string> f = (b) => { return b.ToString(); };
Allows you to call var result = f(b); in the same way.
As a footnote, delegates are a fun part of C#/.NET but usually, the way to control access is to make another method inside your class, and declare it private. If your issue is name conflicts, then you might want to refactor. For example, you can group methods in another class declared inside your original class (nested classes are supported) or move them to another class entirely.
You can use action delegates
public abc() {
Action action = () =>
{
//Your code here
}
action();
}
Edit: To pass parameter
public abc() {
Action <string>action = (str) =>
{
//Your code here
};
}
action("hello");
Using Func to return a value
public void abc() {
Func<string, string> func = (str) => { return "You sent " + str; };
string str = func("hello");
}
You CAN create a nested class:
public class ContainingClass
{
public static class NestedClass
{
public static void Method2()
{
}
public static void Method3()
{
}
}
}
Then yu can call:
ContainingClass.NestedClass.Method2();
or
ContainingClass.NestedClass.Method3();
I wouldn't recommend this though. Usually it's a bad idea to have public nested types.

How does the keyword delegate work compared to creating a delegate

I'm slowly getting my head around delegates, in that the signature of the delegate must match that of the method it is delegating too.
However, please review the following code.
public static void Save()
{
ThreadStart threadStart = delegate
{
SaveToDatabase();
};
new Thread(threadStart).Start();
}
private static void SaveToDatabase() { }
I am now stumped at this point, because the delegate returns void (as that is what SaveToDatabase() is) but, it's clearly returning a ThreadStart... Or is it?
If I were to write my own delegate, I would have no idea how to achieve this because the delegate would have to be void to match the return type of SaveToDatabase(). But it can't be; it would be of type ThreadStart!
My question is, have I totally mis-understood or is this made possible by some .NET trickery? If I wanted to write this method but create my own delegate, how would I ?
The word "delegate" is a bit abused. It's easier with classes and objects. A "class" is like a blueprint for an object. An "object" is an actual instance in memory, which follows the blueprint of the class.
For delegates we use the same word, hence I suspect your confusion. Consider the following code:
class Main
{
public delegate int DelegateType(string x);
public int SomeFunction(string y) { return int.Parse(y)*2; }
public void Main()
{
DelegateType delegateInstance = null;
delegateInstance = SomeFunction;
int z = delegateInstance("21");
Console.WriteLine(z);
}
}
This code outputs "42".
The DelegateType is the type of the delegate. Like a class is a blueprint for an object, the delegate is a blueprint for a function.
So later we create a variable named delegateInstance which is of the type DelegateType. To that variable, we can assign ANY function that takes a single string parameter and returns an integer. Note, that we assigned the function itself, not the results of that function. It's like the delegateInstance variable is now a synonym of that function. Indeed, as demonstrated a line later, we can now use delegateInstance to call that funcion! Just as if delegateInstance was a function itself. But, since it is variable, we can also do all the same things that we usually do with variables - like pass them as parameters to other functions, or even return from other functions (A function that returns a function! Wrap your head around that!)
OK, let's see the code that baffled you.
public static void Save()
{
ThreadStart threadStart = delegate
{
SaveToDatabase();
};
new Thread(threadStart).Start();
}
private static void SaveToDatabase() { }
First thing to notice is that you used an anonymous delegate. Another misuse of the term. When compiled, it results in something like this:
public static void Save()
{
ThreadStart threadStart;
threadStart = __ASDASDASD6546549871;
var tmp = new Thread(threadStart);
tmp.Start();
}
private static void SaveToDatabase() { }
private void __ASDASDASD6546549871()
{
SaveToDatabase();
}
Note that your anonymous function was actually transformed to a completely regular function with a random name, and then that function was assigned to the threadStart variable.
So now this is just like the example above. Just replace DelegateType with ThreadStart, delegateInstance with threadStart and SomeFunction with __ASDASDASD6546549871.
Does it make sense now?
I am now stumped at this point, because the delegate returns void (as that is what SaveToDatabase() is) but, it's clearly returning a ThreadStart... Or is it?
If I were to right my own delegate, I would have no idea how to achieve this because the delegate would have to be void to match the return type of SaveToDatabase(), but can't be because it would be of type ThreadStart!
ThreadStart is defined as a delegate. In fact, it is defined as
public delegate void ThreadStart();
So your code is not returning a delegate or a ThreadStart. It is simply defining a function that matches the ThreadStart delegate definition. The Thread constructor expects a ThreadStart delegate, which you have defined as the variable threadStart, which points to the SaveToDatabase function.
I tend to think of delegates as the old C++ term "function pointers". Delegates allow us to specify what kind of function (parameters and return type) should be passed as a parameter to another function.
My question is, have I totally mis-understood or is this made possible by some .NET trickery? If I wanted to write this method but create my own delegate, how would I ?
I think you may have misunderstood. But to answer this question specifically, the method you would write would just need to match the definition specified by the delegate type, in this case ThreadStart. That method definition must return void and accept no parameters. Your SaveToDatabase method matches this delegate type and is therefore the proper delegate method to create.
When you are going to run an administrated subProcess, the method that is going to be executed gets represented by ThreadStart or ParameterizedThreadStart, but SaveToDatabase is void and it will be executed with void signature, not with ThreadStart type.
Example from MSDN:
class Test
{
static void Main()
{
// To start a thread using a static thread procedure, use the
// class name and method name when you create the ThreadStart
// delegate. Beginning in version 2.0 of the .NET Framework,
// it is not necessary to create a delegate explicityly.
// Specify the name of the method in the Thread constructor,
// and the compiler selects the correct delegate. For example:
//
// Thread newThread = new Thread(Work.DoWork);
//
ThreadStart threadDelegate = new ThreadStart(Work.DoWork);
Thread newThread = new Thread(threadDelegate);
newThread.Start();
// To start a thread using an instance method for the thread
// procedure, use the instance variable and method name when
// you create the ThreadStart delegate. Beginning in version
// 2.0 of the .NET Framework, the explicit delegate is not
// required.
//
Work w = new Work();
w.Data = 42;
threadDelegate = new ThreadStart(w.DoMoreWork);
newThread = new Thread(threadDelegate);
newThread.Start();
}
}
class Work
{
public static void DoWork()
{
Console.WriteLine("Static thread procedure.");
}
public int Data;
public void DoMoreWork()
{
Console.WriteLine("Instance thread procedure. Data={0}", Data);
}
}
From MSDN
A delegate is a type that references a method. Once a delegate is assigned a method, it behaves exactly like that method. The delegate method can be used like any other method, with parameters and a return value, as in this example:
public delegate int PerformCalculation(int x, int y);
So return type of the delegate will match the return type of the method it is delegating.
Any method that matches the delegate's signature, which consists of the return type and parameters, can be assigned to the delegate. This makes is possible to programmatically change method calls, and also plug new code into existing classes. As long as you know the delegate's signature, you can assign your own delegated method.

how to pass function to different DLL included in project as reference

I have referenced one DLL (I have source code of this) say Dll_A in which there is a function
private void uploadPic(int a)
In my main project, I have a function say
private void passMe(int b)
{
}
I need to pass the above function (passMe) to uploadPic function in Dll_A, how can I do that? Is it possible?
I am able to use functions of the Dll_A from my main project, so instantiating isn't a problem, I just need a way to pass function.
===
Thanks, giving it a try. If some can edit code below
//code in main project picbackman.cs
public delegate void delObj(int v);
private void uploadSome(string path, string fName, string str)
{
delObj del1 = new delObj(updatePValue);
UploadFileResponse response = boxProvider1.UploadFiles(args1, folderString, ((Picbackman.BoxProvider.delObj)( del1)));
}
//code in different dll which is referenced in main project //Dll_A
public delegate void delObj(int v);
public UploadFileResponse UploadFiles(string[] filePathes,string folderId, delObj d)
{}
First of all your method will need to accept a delegate as one of it's parameters. That would be something like
private void uploadPic(Action<int> func,int a){
//at some point do func(someInt);
}
at another point declare anothe method or function
public class someClasse {
public vois passMe(int b){
...
}
}
First of all notice that the access modifier has changed. if they are not in the same class you will need to be able to access one from the other so they can't both be private and since they are in different assemblies internal won't work either.
when you need the delegate do like this
var obj = new someClass();
var myInt = 5; //or whatever the value is
uploadPic(obj.passMe,myInt);
notice that the method is used with out arguments. When using a method without arguments the compiler will try and convert it to a suitable delegate.
I'd recommend you not to use delegate but stick with Func/Action they are delegates but more generic
public delegate void DelObj1();
public delegate void DelObj2()
public void F(){};
var del1 = new DelObj1(F);
var del2 = new DelObj2(F);
you can't pass a del1 where a DelObj2 is needed even though you use the same method for each. You will not have that issue if you use Action/Function
Action del1 = F;
Action del2 = F;
The reason is that DelObj1 and DelObj2 are two distinct classes with the same base class Ie they are siblings in the type tree. Using Action the type is the same for both del1 and del2
You should have a look at Delegates.
From the documentation:
A delegate is a type that references a method. Once a delegate is
assigned a method, it behaves exactly like that method. The delegate
method can be used like any other method, with parameters and a return
value
and
Delegates allow methods to be passed as parameters
So in your case you should be able to do something like this:
// define the delegate
public delegate int PictureDelegate(int value)
// define your passMe function (in the class MyClass for example)
public int passMe(int value)
{
return value + 1;
}
// when you want to use it
MyClass myInstance = new MyClass();
PictureDelegate passFunc = new PictureDelegate(myInstance.passMe);
myDll.uploadPic(passFunc, 12);

Categories

Resources