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));
}
Related
I am preparing for an exam and I have to examine various codes. One is about delegates in C# - I'm failing to see what it does, since I don't know if you can put functions from two different classes in one delegate.
Here's the code:
namespace konzolnaApplikacijaDelegateVoidMain {
public delegate int MyDelegate(int x);
class Program
{
public int number;
public Program (int x)
{
number = x;
}
public int Add(int x)
{
return x + 10;
}
public int Substract(int x)
{
return x - 10;
}
public int Multiply(int x)
{
return x * 2;
}
static void Main(string[] args)
{
MyDelegate delegate;
Program first = new Program(20);
Program second = new Program(50);
delegate = first.Add;
delegate += second.Add;
delegate -= first.Substract;
delegate += second.Multiply;
delegate += first.Add;
delegate(first.number);
delegate(second.number);
Console.Write("{0}", first.number + second.number);
}
}
}
Delegates are quite simple. Consider the following implementation of a delegate.
namespace DelegateExamples
{
class Program
{
//Declare a integer delegate to handle the functions in class A and B
public delegate int MathOps(int a, int b);
static void Main(string[] args)
{
MathOps multiply = ClassA.Multiply;
MathOps add = ClassB.Add;
int resultA = multiply(30, 30);
int resultB = add(1000, 500);
Console.WriteLine("Results: " + resultA + " " + resultB);
Console.ReadKey();
}
}
public class ClassA
{
public static int Multiply(int a, int b)
{
return a * b;
}
}
public class ClassB
{
public static int Add(int a, int b)
{
return a + b;
}
}
}
I have to map input from device hardware done with a native driver in that way:
GIS_LF_API.TSLF_SetReaderMode(handle, 1);
GIS_LF_API.TSLF_StartAutoRead(handle, '\r', AutoReadProc);
AutoReadProc is invoked when the input come from the hardware and is defined in that way to call my OnCallback method:
private GIS_LF_API.AutoReadCallback AutoReadProc = OnCallback;
private static int OnCallback(string Arr, int Len)
{
//do somethings
return intValue;
}
where AutoReadCallback into driver is defined like this:
public delegate int AutoReadCallback([MarshalAsAttribute(UnmanagedType.LPStr)] string pData, int Len);
now i want to map an Observable<int> when the event is called.
How is possible to do? I have tried with Observable.FromEventPattern but i have not find a way to map it.
You can either stick an Event around the delegate, then use Observable.FromEvent (probably preferred), or stick a Subject in your handler, and expose the subject as an observable.
Event solution:
public class X
{
public X()
{
AutoReadProc += OnCallback; //If still necessary.
IntObservable = Observable.FromEvent<GIS_LF_API.AutoReadCallback, int>(h => AutoReadProc += h, h => AutoReadProc -= h);
}
public event GIS_LF_API.AutoReadCallback AutoReadProc;
private int OnCallback(string Arr, int Len)
{
//do something, if necessary. Not required for observable.
var intValue = 0;
return intValue;
}
public IObservable<int> IntObservable { get; }
}
Subject solution:
public class Y
{
private readonly Subject<int> _subject = new Subject<int>();
public Y()
{
IntObservable = _subject.AsObservable();
}
private int OnCallback(string Arr, int Len)
{
//do something
var intValue = 0;
_subject.OnNext(intValue);
return intValue;
}
public IObservable<int> IntObservable { get; }
}
I made OnCallback non-static, which differs from your solution. It would still work if static, but the Subject would have to be static as well.
Have a go at this:
void Main()
{
var foo = new Foo();
Observable
.FromEvent<AutoReadCallback, int>(a => (pd, l) =>
{
var r = pd.Length + l;
a(r);
return r;
}, h => foo.AutoReadCallback += h, h => foo.AutoReadCallback -= h)
.Subscribe(x => Console.WriteLine(x));
foo.OnAutoReadCallback("Bar", 2);
}
public delegate int AutoReadCallback(string pData, int Len);
public class Foo
{
public event AutoReadCallback AutoReadCallback;
public int OnAutoReadCallback(string pData, int len)
{
var arc = this.AutoReadCallback;
if (arc != null)
{
return arc(pData, len);
}
return -1;
}
}
It's weird that an event handler returns a value so this code has some redundant looking code.
using System;
namespace _1._75_Using_a_delegate
{
public class Program
{
public delegate int Calculate(int x, int y);
public int Add(int x, int y) { return x + y; }
public int Multiply(int x, int y) { return x * y; }
public void UseDelegate()
{
Calculate calc = Add;
Console.WriteLine(calc(3, 4)); //Displays 7
calc = Multiply;
Console.WriteLine(calc(3, 4));//Displays 12
}
public static void Main()
{
//call and execute UseDelegate()
}
}
}
This should output the above results of 7 and 12.
The delegate function is not directly callable from main in the current state.
Why can't the delegate be seen from main?
Is it necessary to create a class?
How should the delegate function be called?
You cannot call the non-static method from static Method so you have to implement another class like
internal class Check
{
public delegate int Calculate(int x, int y);
public int Add(int x, int y)
{
return x + y;
}
public int Multiply(int x, int y)
{
return x * y;
}
public void UseDelegate()
{
Calculate calc = Add;
Console.WriteLine(calc(3, 4)); //Displays 7
calc = Multiply;
Console.WriteLine(calc(3, 4));//Displays 12
}
}
your call it from your Main Method like
private static void Main(string[] args)
{
new Check().UseDelegate();
}
You don't call the method at all, and you can't now since the Main method is static and your methods are not.
I would recommend to split your code off to a second class, which is easier to call. (Instead of making all methods static)
public class Assignment
{ /* all code except the Main method goes here */ }
Then, in your Main method, instantiate an instance of the Assignment class and call UseDelegate:
public static void Main()
{
Assignment a = new Assignment();
a.UseDelegate();
Console.ReadKey(); // to prevent the console from closing immediate
}
I am studying about delegates. Few days back, I did a sample for a multicast delegates and reviewed here My previous question and clearly understood about multicast delegate.
But now I trying to do a multicast delegate sample with a event. But I got some doubts while doing sample. In the above link, I did all functions and delegate declaration in one class and add the function in to delegate using += and just call the delegate. So all function inside delegate invoked.
But now I am doing it in two different classes and trying to do all functions with the help of a event. I am providing my current code below.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ArithmeticOperations aOperations = new ArithmeticOperations();
aOperations.StartCalculations += new ArithmeticOperations.BasicCalculations(aOperations_StartCalculations);
aOperations.PerformCalculations(20, 10);
}
void aOperations_StartCalculations(string msg)
{
MessageBox.Show(msg);
}
}
class ArithmeticOperations
{
public delegate void BasicCalculations(string msg);
public event BasicCalculations StartCalculations;
public void PerformCalculations(int n1, int n2)
{
StartCalculations("Operation Success");
}
void Add(int num1, int num2)
{
MessageBox.Show("Performing addition.");
}
void Sub(int num1, int num2)
{
MessageBox.Show("Performing substraction.");
}
void Mul(int num1, int num2)
{
MessageBox.Show("Performing multiplication.");
}
void Div(int num1, int num2)
{
MessageBox.Show("Performing division.");
}
}
Here in the Form1 is my main class and ArithmeticOperations class is using for doing functionalities. When on this statement
aOperations.PerformCalculations(20, 10);
in the Form1, the PerformCalculation() function in the ArithmeticOperations class will execute.
But my doubt is how I register all the Add, Sub, Mul and Div function to the delegate in ArithmeticOperations class to invoke all functions by just calling the delegate object and return "Operation Success" to the event callback function in Form1 class ?
Since BasicCalculations takes a single argument of type string, it cannot be used to directly invoke your methods Add, Subtract etc.
If you want PerformCalculations to invoke each of your methods via multicast, you will need a delegate of a type equivalent to Action<int, int>, eg:
class ArithmeticOperations
{
public delegate void BasicCalculations(string msg);
public event BasicCalculations StartCalculations;
private Action<int, int> calculations;
public ArithmeticOperations()
{
this.calculations += this.Add;
this.calculations += this.Sub;
}
public void PerformCalculations(int n1, int n2)
{
this.calculations.Invoke(n1, n2);
StartCalculations("Operation Success");
}
// ...
}
If you want your individual arithmetic methods to invoke your StartCalculations event with a string, you can let them do it like this:
void Add(int num1, int num2)
{
StartCalculations("Performing addition.");
}
When raising events, you should test that there are subscribers first (to avoid a NullReferenceException). The standard pattern is to get any handler subscribed, test for null then invoke the handler. This will avoid hitting a NullReferenceException, if someone unsubscribes after a testing the event for null:
void Add(int num1, int num2)
{
var handler = this.StartCalculations;
if (handler != null)
{
handler("Performing addition.");
}
}
Since that would be a lot of code repetition for each method, you can refactor it into a separate method:
void Add(int num1, int num2)
{
this.OnStartCalculation("Performing addition.");
}
void OnStartCalculation(string message)
{
var handler = this.StartCalculations;
if (handler != null)
{
handler(message);
}
}
one of the options would be creating a private event
public delegate void BasicCalculations(string msg);
public delegate void DoMath(int na, int nb);
class ArithmeticOperations
{
public ArithmeticOperations()
{
StartMath += new DoMath(ArithmeticOperations_StartMath);
}
void ArithmeticOperations_StartMath(int na, int nb)
{
Add(na, nb);
Sub(na, nb);
Mul(na, nb);
Div(na,nb);
}
public event BasicCalculations StartCalculations;
private event DoMath StartMath;
public void PerformCalculations(int n1, int n2)
{
StartMath(n1, n2);
StartCalculations("Operation Success");
}
void Add(int num1, int num2)
{
Console.WriteLine("Performing addition.");
}
void Sub(int num1, int num2)
{
Console.WriteLine("Performing substraction.");
}
void Mul(int num1, int num2)
{
Console.WriteLine("Performing multiplication.");
}
void Div(int num1, int num2)
{
Console.WriteLine("Performing division.");
}
}
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();
}
}