Is it possible to achieve in C++ similar behavior to that of events with custom arguments in C#?
I came across the following link:
https://www.tangiblesoftwaresolutions.com/articles/cplus_equivalent_to_csharp_events.html
Can that idea be applied to a situation where custom event args are used?
An example of C# code to be mimicked or implemented in C++ is below. For context, this is part of an (WinForms) application using the MVC architecture pattern.
// part of service layer of Model
// the View is subscribed to this class
public static class ModelService
{
// methods for using data access layer to interact with database...
// event for getting all customers
public static event EventHandler<GetAllCustomersEventArgs> OnGetAllCustomers = delegate { };
// custom event args
public class GetAllCustomersEventArgs : EventArgs
{
private List<Customer> customerList;
// ctor
public GetAllCustomersEventArgs(List<Customer> customerList)
{
this.customerList = customerList;
}
public List<Customer> getList()
{
return this.customerList;
}
}
}
// part of View
// subscribed to Model
public partial class ViewCustomersForm : Form
{
public ViewCustomersForm
{
// subscribe to the required Model events
CustomerOps.OnGetAllCustomers += new EventHandler<GetAllCustomersEventArgs>(customerEventHandler);
}
private void customerEventHandler(object sender, GetAllCustomersEventArgs e)
{
populateView(e.getList());
}
}
The idea is to implement this in a WxWidgets application in the future.
I understand that in C++, function pointers are equivalent to the use of delegates in C#. However, I am unfamiliar with the concept of function pointers, and seeking some guidance on how to use them in the context of what is desired to be achieved as described above, with perhaps some example code.
Related
suppose we have this scenario :
a class that you are not allowed to modify anything in it :
public class ForbiddenClass_A
{
public void TheMethod()
{
//do stuff
}
}
and another read only class that calls a method from the previous class:
public class ForbiddenClass_B
{
ForbiddenClass_A fc_a;
void Update()
{
//some logic that if true it will call :
fc_a.TheMethod();
}
}
Now you have your class, that you do anything to it, and from it you want to know if TheMethod() :
public class MyClass
{
//call this when TheMethod() from ForbiddenClass_A is called.
public void TheMethod_Catcher()
{
}
}
Thank you!
Is there a way to catch a method call without subscribing it to any
sort of Events?
Decoupled messaging is probably where you want to be, event aggregator or any other pub sub method messaging system. Although you still have to subscribe to something, the participants need not know about each other allowing you to make the methods private.
Unity, MvvmLight both have these sorts of messaging systems, however they are truly dime-a-dozen, there are plenty
Example of how this might work
public CreateUserForm()
{
InitializeComponent();
EventPublisher.Instance.Subscribe<NewUserCreated>
(n => listBoxUsers.Items.Add(n.User.Name));
}
...
// some other class
private void Update()
{
var user = new User()
{
Name = textBoxUserName.Text,
Password = textBoxPassword.Text,
Email = textBoxEmail.Text
};
EventPublisher.Instance.Publish(new NewUserRequested(user));
}
Update
There are injection techniques if you are interest for .net
Dynamically replace the contents of a C# method?
I am new to C# and programming in general and am trying to figure out how to use events. Previously I have been programming with ActionScript3, and there events are a special class that you inherit from if you want to create your own events, and then that event can be called by any other class.
With C# I have tried to do something similar, like so:
public class EventManager
{
public delegate void TempDelegate();
public static event TempDelegate eSomeEvent;
}
public class SomeOtherClass
{
//doing some stuff, then:
if (EventManager.eSomeEvent != null)
{
EventManager.eSomeEvent();
}
}
This gives me a compiler error CS0070: The event 'EventManager.eSomeEvent' can only appear on the left hand side of += or -= (except when used from within the type 'EventManager')
The information about this error over on the msdn indicates that I should use += instead of trying to call the event, but I don't really understand this. I'm not trying to subscribe anything from SomeOtherClass to the event delegate, I am just trying to call this event so that it starts executing those functions that are already subscribed to that event.
So is it possible to do it this way? If not, is it at all possible to call an event that is of one class, from another class? I simply wish to reuse certain events in my classes rather than creating many similar ones in multiple classes.
Any advice with this would be greatly appreciated!
You can wrap the event call in a public method and use that from your other classes.
public void OnSomeEvent()
{
var handler = eSomeEvent;
if (handler != null) handler(this, null);
}
However you might want to look at the design again, if you are really sure the event should be on a different class than the one triggering it.
Well, the typical solution is to put eSomeEvent invocation into the EventManager class
public class EventManager
{
public delegate void TempDelegate();
public static event TempDelegate eSomeEvent;
// Not thread safe as well as your code
// May be internal, not public is better (if SomeOtherClass is in the same namespace)
public static void PerformSomeEvent() {
if (!Object.ReferenceEquals(null, eSomeEvent))
eSomeEvent(); // <- You can do it here
}
}
public class SomeOtherClass
{
//doing some stuff, then:
EventManager.PerformSomeEvent();
}
The class hierarchy and the code is like the below:
And how to call GetInvocationList() to see how many functions have been bound to the Added delegation in the Main function?
namespace Test
{
public class Program
{
public class SelectSet
{
public event SelectSet.AddedEventHandler Added;
public delegate void AddedEventHandler(object BusinessObject);
}
public class C1
{
public static SelectSet SelectSet;
}
static void Main()
{
}
}
}
And how to call GetInvocationList() to see how many functions have been binded to the Added delegation in the Main function?
You can't (at least without reflection), and you shouldn't. The point of exposing an event is to only expose functionality to add or remove handlers. So it's a bit like your code was written like this:
public class SelectSet
{
// Private fields here
public void AddAddedHandler(SelectSet.AddedEventHandler handler)
{
// Implement using private fields
}
public void RemoveAddedHandler(SelectSet.AddedEventHandler handler)
{
// Implement using private fields
}
public delegate void AddedEventHandler(object BusinessObject);
}
If you look at that class, it's pretty obvious that from the outside you won't be able to find out what handlers there are. Just because you're declaring a field-like event doesn't give the outside world access to your field.
You can expose the handlers explicitly if you want, of course - but it's rarely a good idea.
See my article on events and delegates for more information.
In VB at least, the delegate is available as Private <EventName>Event, so you could retrieve AddedEvent.GetInvocationList directly from within the class, or using reflection from outside.
I have WinForms app with MVC pattern implemented, where Model is running asynchronously (backgroundWorker thread) from View (Form). View is subscribed to couple of events that are raised from Model.
Now I need to convert this to WCF app, where event-eventHandler concept has to be present.
At first, I wanted to implement this via callback interface, but in my case one method from Model is raising more than one type of events, and I am constrained on usage of single callback interface when defining service contract.
At this moment I came up with the idea of specifying different type of events as methods in callback service and implement it in client. For example:
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void EventHandler1();
[OperationContract(IsOneWay = true)]
void EventHandler2(string callbackValue);
[OperationContract(IsOneWay = true)]
void EventHandler3(string callbackValue);
}
Should I go along with this solution or there are some better alternatives (publish-subscribe wcf pattern)?
Sounds like you definitely want pub/sub architecture here.
Take a look at Juval Lowy's Publish-Subscribe Framework from this MSDN article:
http://msdn.microsoft.com/en-us/magazine/cc163537.aspx
You can use single method with a base type parameter to activate your call. Then in your service code, jump to specific handler based on the type of the event.
public class BaseEvent { }
public class MyFirstEvent : BaseEvent { }
public class MySecondEvent : BaseEvent { }
public class MyThirdEvent : BaseEvent { }
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void EventHandler(BaseEvent myEvent);
}
public class MyService : ICallbacks
{
public void EventHandler(BaseEvent myEvent)
{
//Now you can check for the concrete type of myEvent and jump to specific method.
//e.g.:
if (myEvent is MyFirstEvent)
{
//Call your handler here.
}
//Another approach can be predefined dictionary map of your event handlers
//You want to define this as static map in class scope,
//not necessarily within this method.
Dictionary<Type, string> map = new Dictionary<Type, string>()
{
{ typeof(MyFirstEvent), "MyFirstEventHandlerMethod" },
{ typeof(MySecondEvent), "MySecondEventHandlerMethod" }
{ typeof(MyThridEvent), "MyThirdEventHandlerMethod" }
};
//Get method name from the map and invoke it.
var targetMethod = map[myEvent.GetType()];
this.GetType().GetMethod(targetMethod).Invoke(myEvent);
}
}
Using a Duplex is not a good idea unless your application runs on the same at least on the same network and there are not proxies, etc to interferer with. You will also end up with a tight coupling between publisher and subscriber.
I usually try to encapsulate my web service calls in my client side apps.
Rather than doing this:
public Guid FindUserIDSelected(string userName)
{
MyWebServiceReference service = new MyWebServiceReference(GetEndpointBasedOnEnv(Env));
return service.GetUserIDFromName(userName);
}
I have a static class that encapsulates the communication with the web services. It handles the endpoint resolution via determining the environment (and other such things).
So the above code changes to look like this:
public Guid FindUserIDSelected(string userName)
{
return Communication.GetUserIDFromName(userName);
}
But now I am having an issue. Silverlight only supports Asynchronous calls (at least as far as I am seeing). So calling a web service and then returning the value in an encapsulated call does not work.
The best I can come up with is passing in a delegate that is used in the Communication class for the completed event:
private Guid foundUserID;
public void FindUserIDSelected(string userName)
{
Communication.GetUserIDFromName(userName, GetUserIDCompleted);
}
private void QuestionRecieved(object sender, GetUserIDFromNameCompletedEventArgs e)
{
foundUserID= e.Result();
}
This has several problems (in my opinion).
I now have elements of the web services that have broken encapsulation (the completed call is really the web service return. I don't want the rest of my classes to have to care about the services).
I have had to expose my result (foundUserID) at the class level.
Am I being too rigid? Is that good enough? Is there a better way?
Am I the only one who has this issue?
In my opinion, it'd better to use eventing from your communication class, especially if you have some thing like [EventAggregator]1, so you can filter an event based on your specific argument
Below is the code snippet, this may be helpful for you.
public static class Communication
{
public static event EventHandler<MyEventArgs> ServiceCallComplete;
public static void InvokeMyAcionComplete(MyEventArgs e)
{
EventHandler<MyEventArgs> handler = ServiceCallComplete;
if (handler != null) handler(null, e);
}
public static void CallService ()
{
//Performed async call
// Fire the event to notify listeners
OnServiceCalled();
}
private static void OnServiceCalled ()
{
InvokeMyAcionComplete(new MyEventArgs());
}
}
public class ClientCode
{
public void CallService()
{
Communication.CallService();
//Subscribe to the event and get notified when the call is complete
Communication.ServiceCallComplete += OnServiceCalled;
}
private void OnServiceCalled(object sender, MyEventArgs e)
{
//MyEventArgs is your customized event argument
//Do something with the result
}
}
Hope this help