I am using delegate to use invoke method with 2 parameters. but it is giving null reference exception error:
Object reference not set to an instance of an object.
Unable to shift control to invoke method in main page. Can anyone tell me why its so..? thanks ..
public override event ResponseRecievedDelegate ResponseRecieved;
if (reqName == REQUEST_NAME.abc)
{
IJsonParser parser = new JsonParser();
Object resp = parser.GetData(responseString );
ResponseRecieved.Invoke(reqName, resp); // unable to invoke this method giving null exception ..
}
invoke method implementation is like:
private void OnResponseReceived(REQUEST_NAME requestName, Object response)
{
if (requestName == REQUEST_NAME.abc)
{
//------------
}
else if (requestName == REQUEST_NAME.def)
{
//------------
}
}
you need to check
if(ResponseRecieved != null)
before calling the event
in general, when using events, before using them we need to check for null. you can read here on the subject
Invoking an event - Once a class has declared an event, it can treat
that event just like a field of the indicated delegate type. The field
will either be null, if no client has hooked up a delegate to the
event, or else it refers to a delegate that should be called when the
event is invoked. Thus, invoking an event is generally done by first
checking for null and then calling the event.
if you want the OnResponseReceived method to be called you need to register it to the event. you can do it like this:
ResponseRecieved += OnResponseReceived;
make sure OnResponseReceived is in the correct format and you do it before you call the event.
another way will be just call the method...
Related
While looking at an UWP example app, I came across this code. What I don't understand and can't seem to find in google is line 40:
public event PropertyChangedEventHandler PropertyChanged = delegate { };
Says in the comments that it is a multicast event. What does assigning delegate { } do? Does it have anything to do with the comment saying the event is multicast?
What does assigning delegate { } do?
That is simply adding an anonymous function to the event, with an empty body. Since C#3, one would generally use a lambda expression instead:
public event PropertyChangedEventHandler PropertyChanged = (s, e) => { };
However, lambda expressions require each parameter to be elicited, whereas using delegate does not. So if you don't need to use the arguments, then delegate may be more concise.
Microsoft highlight this as the single remaining use case of the delegate syntax for defining an anonymous function:
When you use the delegate operator, you might omit the parameter list. If you do that, the created anonymous method can be converted to a delegate type with any list of parameters. That's the only functionality of anonymous methods that is not supported by lambda expressions. In all other cases, a lambda expression is a preferred way to write inline code.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/delegate-operator
Does it have anything to do with the comment saying the event is multicast?
No; multicast means that you can add more than one handling function to the event, and when the event is raised, each one is invoked.
For example:
class Example
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseEvent()
{
PropertyChanged?.Invoke(default, default);
}
}
var example = new Example();
// Use the += operator to add a new handler (rather than = which overwrites)
example += delegate { Console.Writeline("Handler 1"); };
example += delegate { Console.Writeline("Handler 2"); };
example.RaiseEvent();
// Output:
// Handler 1
// Handler 2
Follow up question: What is the purpose of assigning an anonymous function to the event?
If no handler has been added, invoking the event can cause a NullReferenceException, so assigning an empty handler could remove the necessity to handle null.
So the event can be raised like this:
PropertyChanged.Invoke(default, default);
Or this:
PropertyChanged(default, default);
Rather than this:
PropertyChanged?.Invoke(default, default);
It's just an empty delegate, but the compiler will derive delegates from MulticastDelegate. So all delegates in C# are multicast.
Action d = delegate { };
// True
Console.WriteLine(d.GetType().BaseType == typeof(MulticastDelegate));
This is the original source-code written in C#
public delegate Unit UnitResolveEventHandler(object sender, ResolveEventArgs args);
public event UnitResolveEventHandler UnitResolve;
public static Unit GetUnitByName(string name) {
Instance.unitsByName.TryGetValue(name, out result);
if (Instance.UnitResolve != null) {
foreach (UnitResolveEventHandler handler in Instance.UnitResolve.GetInvocationList()) {
result = handler(Instance, new ResolveEventArgs(name));
}
}
}
Using an online translator, I get this VB.NET code:
Public Delegate Function UnitResolveEventHandler(sender As Object, args As ResolveEventArgs) As Unit
Public Event UnitResolve As UnitResolveEventHandler
Public Shared Function GetUnitByName(name As String) As Unit
Instance.unitsByName.TryGetValue(name, result)
If Instance.UnitResolve IsNot Nothing Then
For Each handler As UnitResolveEventHandler In Instance.UnitResolve.GetInvocationList()
result = handler(Instance, New ResolveEventArgs(name))
Next
End If
End Function
The compiler marks the event declaration with this error message:
Events cannot be declared with a delegate type that has a return type.
And the Instance.UnitResolve calls inside the GetUnitByName() method with this error message:
Public Event UnitResolve As UnitResolveEventHandler' is an event, and
cannot be called directly.
How can I properly translate the code from C# to VB.NET without losing functionality?
The customary way of returning a value from an event handler to the invocation of the event is through an argument---either a member of the event arguments class, or through a ByRef parameter on the delegate.
If you have control over ResolveEventArgs and the event handler routines, you could do something like this:
Public Class ResolveEventArgs
'...
Public ReturnValue As Unit
'...
End Class
In the body of your handler (assuming the typical declaration of the event arguments as e), instead of Return (return value):
e.ReturnValue = (return value) 'substitute for (return value) as appropriate
Then, the body of your For Each loop would look like this:
Dim args As New ResolveEventArgs(name)
handler(Instance, args)
result = args.ReturnValue
As an aside, the original C# code has a thread-safety issue. It could throw a NullReferenceException in the event that the last subscribed handler is removed between the null check and reading the invocation list. Whether this is serious (or a concern at all) depends on where and how it's being used. The usual way of addressing this is to store to a temporary, then do the null check and invocation list on the temporary. If you're using a recent version of the .NET languages, then you can skip the null check and use the ?. operator, which should also be safe against the particular thread-safety issue.
The original C# source code is bad; event handlers shouldn’t return values. You’ll have to make it not-an-event:
Public UnitResolve As UnitResolveEventHandler
and use Delegate.Combine manually to add event handler:
Instance.UnitResolve = Delegate.Combine(Instance.UnitResolve, newHandler)
Consider the "application" where an object (Thrower) is throwing a ball to another object (Receiver). The event (BallIsThrowed) happens when the ball is thrown.
Here are the 2 classes :
then the entry point :
And finally the methods pointed by the delegate when events are fired :
This is working well.
Now I want to comment this line :
because I want to say that the ball was not thrown.
The result is a null Exception :
This is normal because at this point BallIsThrowed is null
To solve this, I initilise my event :
But then my problem is that my code is never taking the event when I decomment "receiver.Register(thrower)"
My questions are :
How can I have the 2 method EventMethod fired ?
The best practice way to fire an event looks like this:
EventHandler ballIsThrowed = BallIsThrowed;
if (ballIsThrowed != null)
{
ballIsThrowed(this, EventArgs.Empty);
}
The reason for the temporary variable is to prevent race conditions between the null check and the execution.
Bear with me: you are setting an event handler to BallIsThrowed, then you use IthrowTheBall() to actually trigger the event, with this code:
BallIsThrowed(this, EventArgs.Empty);
When you try to call an event handler, in this case the BallIsThrowed, it must exists or it will throw a NullReferenceException. So, in order for this to work, it must exists an event handler BallIsThrowed. It actually does, until you comment this line:
//BallIsThrowed += new EventHandler(method.EventMethod2);
So basically you need to verify if the EventHandler exists before firing it:
if (BallIsThrowed != null)
BallIsThrowed(this, EventArgs.Empty);
Another (more elegant, if you ask me) way of doing this is:
(BallIsThrowed??delegate{})(this, EventArgs.Empty);
Compact, thread safe...
Two things that need to be corrected:
In your Event Invoker, check EventHandler != null because you dont know if anyone registered to your handler.
var ballThrown = BallIsThrowed;
if (ballThrown != null)
{
ballThrown(this, EventArgs.Empty);
}
For general knowledge, In order to register more then one delegate to your
EventHandler, dont register it via the = operator, but via the
+= operator, meaning you want to append a new delegate:
public void IThrowTheBall()
{
// Do stuff
// You dont have to register this delegate, you can append it to the current
// delegates already registered
BallIsThrowed += method.EventMethod1;
}
System.Security.VerificationException:
Operation could destabilize the
runtime.
at Connance.CommunicatorApi.ReportApiClient.AcknowledgeRecallsAsyncDynamicHandler(Object
, AcknowledgeRecallsCompletedEventArgs
)
That's the error I'm getting. What I'm trying to do (background) is create a global event handler for a class of methods. I'm working with a Static Proxy in WCF and I need to create a layer which tracks all the calls and returns to all of the WCF web methods. Unfortunately, WCF strongly types the "Completed" events' EventArgs, making it nearly impossible.
I decided to try something. If an event is EventHandler<SomeSpecificEventArgs>, I can still register a method of signature void Method(object, object) to handle the event. Great. So I set off to create a DynamicMethod which would call my global handler, and register it to each event.
I tried two ways:
1) DynamicMethod is of type void
(object, object)
2) of type void (object,
SomeSpecificEventArgs) -- I use a
generic method for this to get the
type.
Only, when I try to invoke the method, either manually or for the event, I get the above exception.
Here's my code:
// The handler for all callbacks.
// in the example it does nothing.
public void Handler(object sender, object e)
{
dynamic evtArgs = e;
object userState = evtArgs.UserState;
}
private string GetIdentifier(Delegate d)
{
return string.Concat(d.Method.DeclaringType, '.', d.Method.Name);
}
// Method to register an event handler
public void Register<T> (Delegate o) where T : EventArgs
{
// get some info
/* snip. code to get method name, and calculate name of event */
var eventInst = ownerType.GetEvent(eventName);
// The following works, for example:
// someObj.MethodCompleted += Handler;
// even though MethodCompleted is an event of type EventHandler<SomeSpecialEventArgs>
// get the actual type of handler
var handlerType = eventInst.EventHandlerType;
EventHandler evtHandler = new EventHandler(Handler);
DynamicMethod dm = new DynamicMethod(
GetIdentifier(o) + "DynamicHandler", // set the name
typeof(void), // return void
new[] { typeof(object), typeof(T) });// params object and type of event args
ILGenerator gen = dm.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0); // load first arg to stack for calling
gen.Emit(OpCodes.Ldarg_2); // load second arg to stack for calling
gen.Emit(OpCodes.Call, evtHandler.Method); // call method
gen.Emit(OpCodes.Ret); // return
// this is the final delegate
var superdlg = dm.CreateDelegate(handlerType);
// the problem beings here:
// when the event is raised and the delegate is invoked
// of if I dynamicInvoke it, I get the error
eventInst.AddEventHandler(ownerInst, superdlg);
}
edit:
I see. It turns out I have another issue. I'm working in Silverlight. I managed to reproduce my scenario in a separate project and I got it working by using the overload of DynamicMethod which allows you to set an owner. I then specify
DynamicMethod dm = new DynamicMethod("TestMethod2", typeof(void), new[] { typeof(MyClass), typeof(string), typeof(string) }, typeof(MyClass));,
and use ldarg.0, ldarg.1, and ldarg.2. But this is a security critical constructor and won't run on silverlight. I'm just not sure how I need to set it up then. Do I make the Handler public static and load args 0-1? I end up getting an error like this:
Attempt by method
'DynamicClass.TestMethod2(System.String,
System.String)' to access method
'dynamicass.MyClass.Handler(System.String,
System.String)' failed."}
Method arguments are zero indexed - use ldarg.0 and ldarg.1 instead of ldarg.1 and ldarg.2
Theres also a problem with calling the event handler method - you're not specifying the this pointer for the method (Delegate.Target). You need to provide a this pointer, which may or may not be static depending on what is registered.
This also doesn't take care of multicast delegates - this would only call one of the handlers registered on the event. What you need to do is produce a method something like this:
.method public static CallEventHandler(EventHandlerType ev, object sender, EventArgsType e) {
ldarg.0 // the Invoke 'this' pointer
ldarg.1
ldarg.2
callvirt instance void EventHandlerType::Invoke(object, EventArgsType)
ret
}
This uses the event's Invoke method, which deals with calling all the registered handlers for you.
Ok, so what I came up was with this.
Make the Handler method an instance method, and add another argument type for the DynamicMethod constructor of the type of the class that owns it (for the implicit this argument).
then you do dm.CreateDelegate(_args_, this)
I am building a simple class to hold related methods. Part of this code includes synchronising to a database. The built in SyncOrchestrator class includes a SessionProgress event handler which I can wire up an event to.
What I would like to do is instance my class and then hook up an some code to this event so that I can display a progress bar (ill be using BGWorker).
So, my question is probably c# 101, but how do I expose this event through my class the correct way so that I can wire it up?
Thanks
I think you're looking for something like this:
(I also suggest you read the Events tutorial on MSDN.)
public class SyncOrchestrator
{
// ...
public event EventHandler<MyEventArgs> SessionProgress;
protected virtual void OnSessionProgress(MyEventArgs e)
{
// Note the use of a temporary variable here to make the event raisin
// thread-safe; may or may not be necessary in your case.
var evt = this.SessionProgress;
if (evt != null)
evt (this, e);
}
// ...
}
where the MyEventArgs type is derived from the EventArgs base type and contains your progress information.
You raise the event from within the class by calling OnSessionProgress(...).
Register your event handler in any consumer class by doing:
// myMethodDelegate can just be the name of a method of appropiate signature,
// since C# 2.0 does auto-conversion to the delegate.
foo.SessionProgress += myMethodDelegate;
Similarly, use -= to unregister the event; often not explicitly required.
Like this:
public event EventHandlerDelegate EventName;
EventHandlerDelegate should obviously be the name of a delegate type that you expect people to provide to the event handler like so:
anObject.EventName += new EventHandlerDelegate(SomeMethod);
When calling the event, make sure you use this pattern:
var h = EventName;
if (h != null)
h(...);
Otherwise you risk the event handler becoming null in between your test and actually calling the event.
Also, see the official documentation on MSDN.