Delegate Subtractive Assignment - c#

In C#, delegate behave more like a list of function pointers, so that we can call a list of methods with the same method signature via a delegate.
After the initial assignment, we can add or subtract methods from a delegate using += (additive assignment) and -= (subtractive assignment).
Say, I have two methods.
public static void Method1(string message){
// ...
}
public static void Method2(string message){
// ...
}
Now, I declare a delegate type,
public delegate void Del(string message);
If I want to execute Method1, Method2 and again Method1 in order, I can create a delegate like this.
Del delList = Method1;
delList += Method2;
delList += Method1;
Then, later in the program, If I remove Method1 from it, which occurrence of Method1 is removed? Is there any rule governing that?
I believe that the better and more readable way is to create a new delegate and add methods you want excute in order, instead of changing an existing one. I'm just curious about how -= operator is implemented for C# delegates.

If the matching performed by -= doesn't remove the one you wanted, you can call GetInvocationList(), manipulate it how you want, and make a new delegate.
However, that's only possible when you have access to the delegate. For fields, which only have operator+= and operator-= (subscribe and unsubscribe) behaviors, you'd best avoid duplicates if you care about the order of the calls.
Actually, it would probably be best to avoid duplicates altogether.
To answer the question about the specific behavior (though I still maintain that relying on it is far too confusing), operator-= uses Delegate.Remove, which is documented as:
Removes the last occurrence of the invocation list of a delegate from the invocation list of another delegate.
(The documentation for the Delegate class itself says "Managed languages use the Combine and Remove methods to implement delegate operations. Examples include the AddHandler and RemoveHandler statements in Visual Basic and the += and -= operators on delegate types in C#.")

Related

How to add methods to the invocation list of a delegate without instantiating the delegate?

I have to add multiple methods to the invocation list of a delegate. However, all of them have decision logic associated with them. So, there's an if block before the method gets attached to the invocation list of the delegate. Can I do this without instantiating the delegate. The code snippet looks like the following:
public delegate void SomeDelegate();
static void Method1() {}
static void Method2() {}
static void AddMethodsToInvocationList()
{
SomeDelegate someDelegate = new SomeDelegate();
if (someLogic1) someDelegate += Method1;
if (someLogic2) someDelegate += Method2;
}
Basically, I wish to be able to create an instance of the delegate without passing any methods as parameters. However I get a compiler error with "does not contain a constructor that takes 0 arguments" error, if I try and instantiate the delegate without passing any methods as parameters.
I would also be open to solving this issue a different way if someone else has a better way of doing it. However, delegates have to be used.
Thank you for any help. Much appreciated.
You can simply initialize it to null. That is the idiomatic value for a multicast delegate that doesn't have any operations added to it.

How to create hooks in c# using delegates

So this might be something really easy but I wanted to see if the concept of delegate would be appropriate.
I have the following method say on my main
PrintName();
GetId()
If I wanted to add "GetPhone()" Inject it if you will on my main, do I use delegate to this ?
My thought is the compiler will call main and only recognize methods on there, and has no idea if GetPhone() exist (since I just added it somewhere in the folder), the reasoning for this kind of architecture, is that I wanted to be able to just create a plug and play concept.
Thank you.
Sure. Instead of calling the functions directly, you can use a delegate and then call the delegate, like this:
delegate void GetThings();
public GetThings myDelegate;
Then, you may assign or add functions to the delegate from your "plug and play" object.
myDelegate = PrintName();
myDelegate += GetId();
myDelegate = GetPhone();
As long as the return type is the same, you can add functions to the delegate (i.e. calling the delegate once you can call more than one function).
You will need to implement checks for security, though.

Subscribe to a delegate that was passed as method argument

I'm attempting to build a recurring programming pattern into a generic class for code re-use. Part of this pattern thread-safely subscribes/unsubscribes to a delegate as needed during asynchronous operations (multicast delegate used as event).
The following code does not compile. The problem I'm facing is that C# allows me to pass a delegate as method argument, but anywhere inside MyWorker class the subscribe +=,-= operations cause errors. (Works fine on the same delegate from outside).
[Operator '+=' cannot be applied to operands of type 'delegateT' and 'method group']
Syntactical errors?
delegate scope limitation?
is this disallowed by the language?
public class MyWorker<delegateT,argT>
{
private delegateT mDelegate;
public MyWorker(delegateT d)
{
mDelegate = d; //save delegate (reference?) for use later
}
public void DoWorkAsync()
{
mDelegate += m_subscriber; //ERROR: Operator '+=' cannot be applied to operands of type 'delegateT'...
//...Do some work that causes delegate to fire...
mDelegate -= m_subscriber; //ERROR: Operator '-=' cannot be applied to operands of type 'delegateT'...
}
private void m_subscriber(argT arg)
{
Console.WriteLine("Received: " + arg.ToString());
}
}
Note that generics do not seem to be the cause; I've tried using static types instead with the same result. I've also tried passing delegate with the 'ref' keyword to make sure i'm storing and referencing the original object rather than a local copy...maybe a secondary issue, but one step at a time.
[UPDATE]
OIC, inability to constrain Delegate type seems to be a major issue here, and prevents generic usage the way I'm doing it. Thanks for pointing that out Ron.
To clarify the original intent:
I use delegates for internal events; more flexibility than strict 'event' type. I'm searching for some way to pass a delegate (ref?) to MyWorker class at runtime. Then MyWorker performs some background tasks which subscribe and unsubscribe as necessary to receive events during operation, before finally exiting for garbage collection. I do this for 30+ nearly identical tasks/events, which is why creating a reusable (generic?) class is highly desirable.
Delegates in my system have a strict form such as:
delegate void delegateEvent1(Class1 arg);
delegate void delegateEvent2(Class2 arg);
...
delegate void delegateEventN(ClassN arg);
Plan B is to pass Action delegates to subscribe and unsubscribe from within MyWorker. This is quite a bit messier as it requires 2 Actions<> to be created for each invocation rather than just cleanly passing the desired delegate.
Open to any suggestions...
It's not because you named your generic parameter delegateT compiler knows it's some delegate type and so it can't know that some += operator exists on that type.
It would need some generic constraint to enforce this ; but AFAIK that's not possible in C#
As KiwiPiet pointed in comment you can maybe try to add a constraint for some delegate type though
As pointed by Ron Beyer in comment it's also not possible to constraint to some delegate type too

Delegates, Actions, Events, Lambda expression and MVVM

I have spent few days trying to understand WPF and MVVM. It is going very slowly mostly because I have some lack of knowledge in terms of events and stuff. Here bellow I will try to explain my understanding of all this things:
Method – this one is simple and I don't think it needs any explanation. Basic ingredient in any program.
Delegate – the way I see it is pointer on method. I can think of only few applications where I would want to use it over a method.
Action – that one is even trickier. Information I have managed to find say that it is a delegate that doesn't return value... so is it just pointer on void method? I don't see point of that
Event – this one I don't get at all. It was being explained with delegate and I didn't understand how does it work and what is it for. Note I was using events writing winforms applications but it was just choosing desired event from the list.
Event handler – even more unclear.
Lambda expression – also yet another way of using method. Again I understand it doesn't return anything, I can pass some argument in it, but still aint much different from void method. I have seen some applications like when using LINQ but I still don't understand how it works.
I would like to start by saying that I understand basic construct of MVVM, what is doing what and so on. Issue I have is that I don't understand some of the code, how does it work and therefore I can't write anything actually on my own. I will be using some tutorials as example so here it goes:
S1: https://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030
S2: http://social.technet.microsoft.com/wiki/contents/articles/18199.event-handling-in-an-mvvm-wpf-application.aspx
What I am expecting from you guys is some guidance or explanation how can I approach and understand those thinks to make them at least a little less scary for me. Here I will place some examples that will hopefully show you what kind of problems I have.
1) First one comes from S1 from well known RelayCommand class:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
I know what it is suppose to do (name speaks for itself). But I don't understand how this thing works? How it knows when to make something executable and when not. What are exactly those add and remove “commands”? I tried to read about it but it didn't help.
2) Another example form S1:
#region CloseCommand
/// <summary>
/// Returns the command that, when invoked, attempts
/// to remove this workspace from the user interface.
/// </summary>
public ICommand CloseCommand
{
get
{
if (_closeCommand == null)
_closeCommand = new RelayCommand(param => this.OnRequestClose());
return _closeCommand;
}
}
#endregion // CloseCommand
#region RequestClose [event]
/// <summary>
/// Raised when this workspace should be removed from the UI.
/// </summary>
public event EventHandler RequestClose;
void OnRequestClose()
{
EventHandler handler = this.RequestClose;
if (handler != null)
handler(this, EventArgs.Empty);
}
#endregion // RequestClose [event]
Again I know what it is suppose to do, I even understand what is basically happening here but I don't see where this “thing” is actually doing something. OnRequestClose() is just creating handler that in my eyes doesn't do anything to close whatever it is suppose to close. Problem is that if I even don't see where command is executed how can I write my own commands.
3) I think this will be last example, this time from S2:
public ViewModel()
{
_clickCommand = new DelegateCommand<string>(
(s) => { /* perform some action */ }, //Execute
(s) => { return !string.IsNullOrEmpty(_input); } //CanExecute
);
}
Here problem is pretty simple. It is creating command using RelayCommand ctor (or at least it's version in this project, here called “DelegateCommand”). I don't understand those (s) and use of lambda. What is it for?
Of course that isn't everything I have problem with but I think that will give idea what is my problem to anyone willing to help. I tried to explain my problem as best as I can and I would really appreciate any help or guidance. Maybe I am expecting to much from myself but I feel like I need to know all that stuff in order to write anything serious.
Anyway thank you all in advance for any help.
A long answer for your broad question.
Let me dig into Events and EventHandler first using a simple approach
Suppose there is a big function organized in your city which will host many famous people from your country.
Let's consider three guest's for this example
Guest one is a person who is unknown by other guests
Guest two is a famous person from your area and very few people know
Guest three is very famous across your country
Consider the following assumptions
Nobody is waiting for guest one (0 EventHandler)
There are four
people who are waiting for guest two (4 EventHandler's each person is
an event handler waiting to greet)
There are three security personnel and 10 guests (out of which one
person is also waiting for guest 2) waiting for guest 3 (13
EventHandler's)
Scenario 1
When guest one arrives at the venue (Event raised) nothing happens
Scenario 2
When guest two arrives at the venue (Event raised) the four people move towards him/her and give greetings
Scenario 3
When guest three arrives (Event) you will see security forces providing cover and ten people move towards him/her and give greetings
Simple points to be observed
1. Event is just a notification that something has happened (like a delegate with a method signature)
2. EventHandler is an action as to what happens when a specific event has happened ( a method which implements the method signature defined
by the delegate)
3. One event can have many eventhandlers (e.g.. scenario 2,3). Hence the syntax += in the below code sample
The below code will answer some of your basic questions
class Program
{
static void Main(string[] args)
{
var test = new Example();
Console.ReadLine();
}
}
class Example
{
//This is the event definition
delegate void ActionDelegate(string input1, string input2);
// Two event handler which implements the signature of the event
void ActionMethod(string a, string b)
{
Console.WriteLine(a + " " + b);
}
void ActionMethod2(string c, string d)
{
Console.WriteLine("Wow one more function called with parameter {0} and {1}", c, d);
}
delegate Tuple<string, string> LamdaDelegate(string input1, string input2);
public Example()
{
//Did not declare any delegate member variable explicitly.
//Clean and easy to understand
Action<string, string> action = ActionMethod;
// Had to define the delegate with method signature explicitly before using it
ActionDelegate actionDelegate = ActionMethod;
actionDelegate += ActionMethod2; // Attaching more event handlers to the event
//The below lambda expression implicitly means that it will take two inputs each of type string
// and does not return anything.
//The type information is implicitly derived from the method signature of the delegate
actionDelegate += (a, b) => Console.WriteLine("Called using lambda expression");
//Below is a Lambda expression in which s and e each is of type string
//Since the return type of the delegate is Tuple<string,string> the same is returned by the expression
//Lambda expression is using a delegate without defining a delegate explicitly.
LamdaDelegate myTuple = (s, e) => { return Tuple.Create(s, e); };
//The above Lambda can be rewritten as
myTuple += delegate (string a, string b) { return Tuple.Create(a, b); };
//Invoking the event handlers. The event handlers are executed automatically when ever the event occurs
action("Hi", "called from action");
actionDelegate("Hi", "called using explicitly defined delegate");
}
}
Why should we use delegates?
In the above example you saw that the ActionMethod is used by two different delegates(read Event).
Without delegates the above example would be dirty and unreadable.
The above example also shows Action which simplifies the need to define delegates explicitly.
Now comming to Commands
In MVVM the traditional event is replaced by Command and the event parameters (read delegate method signature) is replaced by CommandParameter
In your 3rd question the DelegateCommand has a type parameter which is string. So the (s) you see is a variable which stores the input string sent from UI. Now it is upto you to decide if you want to use the input (s) or ignore it all together. In the CanExecute part you can see that even when the input (s) is passed it has ignored it and uses the other member variable _input.
The 2nd question an event RequestClose is defined which is attached an event handler in Figure 7 of the link. Also observe that in the same figure the MenuItem is bound to the CloseCommand in the ViewModel.
So now when you click on the MenuItem the CloseCommand is invoked and it then calls the function OnRequestClose. The first thing this function checks is that is there anyone interested(read listening) in the event RequestClose which the MainWindow is listening and hence calls the window.Close()
For more clarification please do let me know.
EDIT
The code example above was just for Action<T> and delegate.
In layman terms let me put it this way
If I want to do something based on some external action I would use Event . I will just define an event and wire it up to an EventHandler and just wait for the action to occur. (In the example above I don't know when will the guest arrive but whenever they do arrive the EventHandler will respond automatically)
On the other hand I will use delegate if I want to call single/multiple functions simultaneously based on some internal condition defined in the code. In the code example above you can see that I had to invoke the delegate manually.
Please ignore the Tuple as it is just a return value with no actual importance.
EDIT 2
The scenario (_) or (s) is similar. Both mean that you will get a parameter as an input but in the first scenario the developer is trying to say that this parameter will not be used or ignored while in the (s) they intend to use it
You can't use just () as this means that the lambda expression does not contain any input parameter which is wrong since the definition says that it will receive a string as an input.
1. Delegate
the way I see it is pointer on method
Correct. However since C# is strongly typed, you need to define, what parameters and return type must the method have. This is what delegates are.
I can think of only few applications where I would want to use it over
a method.
This is not about method vs deledate. When you need to pass method as a parameter, then the parameter is defined using delegate.
2. Action
Action is concrete type of delegate. While delegate can refer to any method, Action says, that it is parameterless method with return type void. Action<string> means that parameter is of type string. Action<string, int> means that the method's first parameter must be of type string and second of type int.
Another concrete example of delegate is Func delegate. Func<bool> means that the method does not have parameters and returns bool. Func<string, bool> means that there is one input parameter of type string and it returns bool.
EventHandler is just another delegate, that represents method with void return type and two input parameters: object and EventArgs
3. Event
just think about Button.Click event. The programmers at microsoft that worked on Button class had to provide a way how to notify your program, that button was clicked. So they defined an event and you can handle the event by providing a method that will execute when the event occurs. The method is called eventhandler.
4. EventHandler
is either used as common name for methods that are assinged to events or it is concrete delegate that defines input and output parameters or it is used as.
e.g: Button.Click += DoSomehing; Click is an event. Method DoSomething is and eventhandler. Is must return void and have two input parameters of type object and EventArgs, because when you look at the definition of click event, you can see concrete delegate type which is EventHandler (or RoutedEventHandler - just another delegate used in WPF in some events).
5. Lambda expression
is very simple. Lambda expression is just another syntax to write a method. Compiler translates lambdas to methods anyway. Lambdas are just syntactic sugar.
following method and lambda are equal
bool IsGreaterThan5(int number)
{
return number > 5;
}
var isGreaterThan5 = new Func<int, bool>(number => number > 5);
for example, if you have an array of integers, then you can use Where linq extention method to filter the array. Intelli sense tells you, that the parameter of Where method is Func<int, bool>. Therefore you need to pass method that takes one parameter of type int and returns bool.
int[] numbers = new []{ 1, 2, 3 4, 5, 6, 7 };
var filteredNumbers = numbers.Where(IsGreaterThan5); //method IsGreaterThan5 is defined in previus example
//just another syntax:
var filteredNumbers = numbers.Where(number => number > 5);
//just another syntax:
var filteredNumbers = numbers.Where(new Func<int, bool>(number => number > 5));
//just another syntax:
Func<int, bool> isGreaterThan5 = i => i > 5; //it does not matter how you name the input parameter
var filteredNumbers = numbers.Where(isGreaterThan5);

Why can't I unsubscribe from an Event Using a Lambda Expression?

This article states You Can’t Unsubscribe from an Event Using a Lambda Expression.
E.g. you can subscribe as follows:
d.Barked += (s, e) => Console.WriteLine("Bark: {0}", e);
but you can't unsubscribe like this:
d.Barked -= (s, e) => Console.WriteLine("Bark: {0}", e);
Why? What's the difference between this and unsubscribing from a delegate, e.g.
EventHandler<string> handler = (s, e) => Console.WriteLine("Bark: {0}", e);
d.Barked += handler;
// ...
d.Barked -= handler;
It all comes down to: when are two delegates considered the same for the purposes of delegate addition / subtraction. When you unsubscribe, it is essentially using the logic from Delegate.Remove, which considers two delegates equivalent if both the .Target and the .Method match (at least, for the simple case of a delegate with a single target method; multicast is more complicated to describe). So: what is the .Method and .Target on a lambda (assuming we are compiling it to a delegate, and not to an expression)?
The compiler actually has a lot of freedom here, but what happens is:
if the lambda includes a closure over a parameter or variable, the compiler creates a method (the method) on a compiler-generated class that represents the capture-context (which can also include the this token); the target is the reference to this capture-context instance (which will be defined by the capture scope)
if the lambda doesn't include a closure over a parameter or variable, but does make use of per-instance state via this (implicit or explicit), the compiler creates an instance method (the method) on the current type; the target is the current instance (this)
otherwise the compiler creates a static method (the method), and the target is null (incidentally, in this scenario it also includes a nifty field to cache a single static delegate instance - so in this scenario, only one delegate is ever created per lambda)
What it doesn't do, however, is compare lots of lambdas with similar looking bodies to reduce any. So what I get when I compile your code is two static methods:
[CompilerGenerated]
private static void <Main>b__0(object s, string e)
{
Console.WriteLine("Bark: {0}", e);
}
[CompilerGenerated]
private static void <Main>b__2(object s, string e)
{
Console.WriteLine("Bark: {0}", e);
}
(the Main here is just because in my test rig those lambdas are inside the Main method - but ultimately the compiler can choose any unpronounceable names it chooses here)
The first method is used by the first lambda; the second method is used by the second lambda. So ultimately, the reason it doesn't work is because the .Method doesn't match.
In regular C# terms, it would be like doing:
obj.SomeEvent += MethodOne;
obj.SomeEvent -= MethodTwo;
where MethodOne and MethodTwo have the same code inside them; it doesn't unsubscribe anything.
It might be nice if the compiler spotted this, but it is not required to, and as such it is safer that it doesn't elect to - it could mean that different compilers start producing very different results.
As a side note; it could be very confusing if it did try to de-dup, because you'd also have the issue of capture contexts - it would then be the case that it "worked" in some cases and not others - without being obvious which - probably the worst possible scenario.

Categories