Am studying about delegates. As I read. I learned that adding more than one function in a delegate is called multicast delegate. Based on that I wrote a program. Here two functions (AddNumbers and MultiplyNumbers) I added in the MyDelegate.
Is the below program is an example for multicast delegate ?.
public partial class MainPage : PhoneApplicationPage
{
public delegate void MyDelegate(int a, int b);
// Constructor
public MainPage()
{
InitializeComponent();
MyDelegate myDel = new MyDelegate(AddNumbers);
myDel += new MyDelegate(MultiplyNumbers);
myDel(10, 20);
}
public void AddNumbers(int x, int y)
{
int sum = x + y;
MessageBox.Show(sum.ToString());
}
public void MultiplyNumbers(int x, int y)
{
int mul = x * y;
MessageBox.Show(mul.ToString());
}
}
Yes, it's an example of a multicast delegate. Note that instead of
new MyDelegate(AddNumbers)
you can typically say just
AddNumbers
because a so-called method group conversion exists that will create the delegate instance for you.
Another thing to note is that your declaration public delegate void MyDelegate(int a, int b); does not have to reside inside another type (here inside the MainPage class). It could be a direct member of the namespace (since it's a type). But of course it's perfectly valid to "nest" it inside a class, as you do, for reasons similar to the reason why you create nested classes.
Actually all delegates in C# are MulticastDelegates, even if they only have a single method as target. (Even anonymous functions and lambdas are MulticastDelegates even though they by definition have only single target.)
MulticastDelegate is simply the base class for all kinds of function or method references in C#, whether they contain one or more targets.
So this:
MyDelegate myDel = new MyDelegate(AddNumbers);
Sets myDel to a MulticastDelegate with a single target. But this line:
myDel += new MyDelegate(MultiplyNumbers);
Updates myDel to a MulticastDelegate with two targets.
Multicast delegates is one of the feature of delegates, it wraps the reference of multiple methods and calls it sequentially and it is also known as Delegate Chaining.
Below is the example of multicast delegates.
// Declare Delegates
public delegate void MultiCast(int num1, int num2);
class Program
{
public void Add(int num1, int num2)
{
Console.WriteLine(num1 + num2);
}
public void Sub(int num1, int num2)
{
Console.WriteLine(num1 - num2);
}
public void Mul(int num1, int num2)
{
Console.WriteLine(num1 * num2);
}
static void Main(string[] args)
{
MultiCast del1, del2, del3, multAddDel, multSubDel;
del1 = new Program().Add;
del2 = new Program().Sub;
del3 = new Program().Mul;
//`There are three ways to define the multicast delegate.`
//1 way
//Adding delegates
multAddDel = del1 + del2 + del3;
multAddDel(10, 10);
//Removing Delegates
multSubDel = multAddDel - del3;
multSubDel(10, 10);
Console.WriteLine();
Console.WriteLine("Second Way");
//2 way
MultiCast multAddDel1 = null;
//Adding delegates
multAddDel1 += del1;
multAddDel1 += del2;
multAddDel1 += del3;
multAddDel1(10, 10);
//Removing Delegates
multAddDel1 -= del3;
multAddDel1(10, 10);
Console.WriteLine();
Console.WriteLine("Third Way");
//3 way
MultiCast multAddDel2 = null;
//Adding delegates
multAddDel2 = (MultiCast)Delegate.Combine(multAddDel2, del1);
multAddDel2 = (MultiCast)Delegate.Combine(multAddDel2, del2);
multAddDel2 = (MultiCast)Delegate.Combine(multAddDel2, del3);
multAddDel2(10, 10);
//Removing Delegates
multAddDel2 = (MultiCast)
Delegate.Remove(multAddDel2, del3);
multAddDel2(10, 10);
Console.ReadLine();
}
}
Related
//Main method
test6 _300er = new(yetan.aa);
_300er.Invoke(45, 78);
test7 _200lr = new(yetan.bb);
_200lr.Invoke(new int[4]);
test8 max8 = new(yetan.dd);
double rty = 45;
max8.Invoke(ref rty);
test9 max9 = new(yetan.cc);
max9.Invoke(78);
test10 neo1 = new(yetan.ee);
neo1.Invoke(out char ytss);
test11 neo2 = new(yetan.ff);
neo2.Invoke('^');
delegate void test6(params int[] h);
delegate void test7(int[] h);
delegate void test8(ref double j);
delegate void test9(double j);
delegate void test10(out char j);
delegate void test11(char j);
class yetan {
public static void aa(int[] y) {
Console.WriteLine("params dude");
}
public static void bb(params int[] y) {
Console.WriteLine("params dude");
}
public static void cc(double y) {
Console.WriteLine("jhjgbrvf");
}
public static void dd(ref double y) {
Console.WriteLine("jhjgbrvf");
}
public static void ee(out char y) {
y = '%';
Console.WriteLine("vvvvvvv");
}
public static void ff(char y) {
Console.WriteLine("vvvvvv");
}
}
I declared a delagate with params,out,ref modifiers and without
And created methods that will correspond to the signatures of the delagates
I have noticed that if I can poinnt delagte test6 which has params modifier to the method
aa that does NOT have a parmas modifier yet It will still work and at the end the params will the method aa will act as if it had the paranms modifier.
and the vice versa is possible too but at the end it ius the delegate that decides whether the method that it is pointing to has the params modifier or not
But for some reason the same is not true with modifiers out and ref
if my delegate test8 did not specify ref its instance would not be able to point to the method dd
Can you please tell me what is the reasoning behind this?
Because a params array is still a regular array, but with syntactic sugar for the call-sites. out and ref however change the behavior of the method (values need to be copied out of the method).
In other words: you can invoke a params method with a real array, but you cannot invoke an out or ref method with a value literal (only with a variable)
Is there a way to declare a singlecast delegate in C#? E.g. so that it would not be possible to have more than one method referenced by the delegate at a single point in time.
I am thinking about a way to achieve flexibility in choosing what implementation to use at runtime, but with some kind of safeguard to prevent multiple actions being triggered to avoid any side-effects, especially with non-void return type delegates.
If the delegate must be an Event. (for example interface implementations etc)
You could use the custom event accessor add/remove. This only works at runtime, so this cannot be detected compiletime.
Here's an example:
private EventHandler _myHandler;
public event EventHandler MyHandler
{
add
{
if (_myHandler != null)
throw new InvalidOperationException("Only one eventhandler is supported");
_myHandler = value;
}
remove
{
// you might want to check if the delegate matches the current.
if (value == null || value == _myHandler)
_myHandler = null;
else
throw new InvalidOperationException("Unable to unregister, wrong eventhandler");
}
}
And just use it as a normal event:
MyHandler += (s, ee) => Console.WriteLine("MyHandler handler");
// if you're lazy, you could support deregistering with null
MyHandler -= null;
It's even possible to use Func<T> instead of EventHandler
You'll need to encapsulate the delegate creation and assignment. Then you can throw an exception if there are more than one handlers. Here's a trivial example
using System;
public delegate int MyDelegate(int x, int y);
public class Wrapper{
private MyDelegate d;
public Wrapper(){
this.d = null;
}
public void Assign(MyDelegate func){
if(d!= null && d.GetInvocationList().Length > 0){
throw new Exception("No more than 1 handlers allowed");
}
Console.WriteLine("Assigned");
this.d+= func;
}
}
public class Program
{
static int Sum(int x, int y)
{
return x + y;
}
static int Difference(int x, int y)
{
return x - y;
}
public static void Main()
{
Wrapper w = new Wrapper();
w.Assign(Sum);
w.Assign(Difference); //throws Exception;
}
}
I am trying to build a dummy exercise for my own interest.
I have one form (form1) with two textboxes (textBox1, textBox2) and a button.
When I click the button, I want to add the numbers passed to the textboxes.
Now, I am trying to complicate things by introducing an Interface with the signatures of the appropriate methods to do the addition (ICalculate) and a class (Calculations) which implements the interface.
Then I have another class called Calc which gets initiated from Form1 by passing an ICalculate object and 2 integers (a,b) in its constructor.
Furthermore, the Calc class has a method (addition()) for adding the two integers, using the ICalculate object and the two integers instantiated at the constructor of the class and display the result on a messagebox.
The problem is that the compiler throws an error saying that the ICalculate object has not been initialized (Object reference not set to an instance of an object.)
The code is the following:
public interface ICalculate
{
int add(int x, int y);
int sub(int x, int y);
}
class Calculations : ICalculate
{
public int add(int a, int b)
{
return (a + b);
}
public int sub(int z, int k)
{
return (z - k);
}
}
class Calc
{
private ICalculate _nc;
private int _x, _y;
public Calc(ICalculate nc, int a, int b)
{
var _nc = nc;
_x = a;
_y = b;
}
public void addition()
{
MessageBox.Show(_nc.add(_x, _y).ToString());
}
}
}
The Form1 Code is the following:
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var a = Int32.Parse(textBox1.Text);
var b = Int32.Parse(textBox2.Text);
var c = new Calc(new Calculations(), a, b);
c.addition();
}
}
Any help appreciated !
The problem is in the constructor of the Calc class.
Specifically, this row:
var _nc = nc;
You should remove the var:
_nc = nc;
What happens is that once you have the var keyword you are actually creating a local variable called _nc in the constructor, and assign the value of nc to it, so the class member called _nc is never initialized.
The compiler (tested on VS 2013) should issue a warning for this:
Field '<your namespace here>.Calc._nc' is never assigned to, and will always have its default value null
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
//create delegate instances
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
//calling the methods using the delegate objects
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
in the above code function called and calling function are in same class.... can we use like both in seperate classes?
if its possible please give an example ......
Surely you can.
Just put your methods in a separate class and create an instance of it to access them:
class Arithmetic
{
int num = 10;
public int AddNum(int p)
{
num += p;
return num;
}
public int MultNum(int q)
{
num *= q;
return num;
}
}
Now call the methods:
class TestDelegate
{
public delegate int NumberChanger(int n);
static void Main(string[] args)
{
//create instance of class
Arithmetic art = new Arithmetic();
//create delegate instances
NumberChanger nc1 = new NumberChanger(art.AddNum); //call with reference
NumberChanger nc2 = new NumberChanger(art.MultNum); //call with reference
//calling the methods using the delegate objects
//add
Console.WriteLine("Value of Num: {0}", nc1(25)); //use it directly because your delegate returns a value
//product
Console.WriteLine("Value of Num: {0}", nc2(5)); //use it directly because your delegate returns a value
Console.ReadKey();
}
}
Note: You don't need getNum() method as you are already returning value from every method and your delegate returns it as well. Also I have removed static from everywhere because it seems you need it.
I am using a delegate type to call multiple functions from a single point. But when I do like that , I am getting the result somewhat wrong.
public delegate int MyDel(int a,int b);
public static int Add(int a, int b) { return a+b; }
public static int Sub(int a, int b) { return a-b; }
public static void Meth_del()
{
int x,y;
MyDel _delegate;
_delegate = Add;
_delegate += Sub;
Console.WriteLine( _delegate(5,4));
}
Here I should get result 9 and then 1 but only 1 is printed. How ?
This is called Closure. This happens because on the call it will execute both of the subscribed methods and you will be shown with end result.
To avoid such behavior you can unsubscribe (_delegate = null), override subscribers (=) or subscribe (+=) after first call is made.
public static void Meth_del()
{
int x,y;
MyDel _delegate;
_delegate = Add;
// Prints out 9.
Console.WriteLine( _delegate(5,4));
// Override subscribtion.
_delegate = Sub;
// Prints out 1.
Console.WriteLine( _delegate(5,4));
}
Also you can use += to add subscribers to the delegate (as you have written in your question).
Even if both methods are called only the the last method in the delegate will return the result.
Furthermore, you have only one call of Console.WriteLine(), a function cannot receive multiple return values.
To achieve what you want you might have to queue your results like this.
public static Queue<int> Results = new Queue<int>();
public static void Add(int a, int b) { Results.Enqueue(a + b); }
public static void Sub(int a, int b) { Results.Enqueue(a - b); }
public delegate void MyDel(int a, int b);
public static void Meth_del()
{
int x, y;
MyDel _delegate;
_delegate = Add;
_delegate += Sub;
_delegate(5, 4);
while (Results.Any())
Console.WriteLine(Results.Dequeue());
}
Your code does execute both methods but it only displays the return value of the last added method. If you change your methods like this:
public static int Add(int a, int b) {
Console.WriteLine(a+b);
return a+b;
}
public static int Sub(int a, int b) {
Console.WriteLine(a-b);
return a-b;
}
you will see that 9 as well as 1 are written in the console.
Yes its quite obvious that the last method in the delegate will returns the result.
public static void Meth_del()
{
int x,y;
MyDel _delegate;
_delegate = Add;
Console.WriteLine( _delegate(5,4));
_delegate += Sub;
Console.WriteLine( _delegate(5,4));
}