I have two classes, below is a break down on what's going on before I go on to ask my question...
myClass1:
myClass1(){
myClass2 c2 = new myClass2();
c2.service();
}
public void myFunction1(){
Console.Write("Function returned!");
}
myClass2:
public void service(){
callWebService(myFunction1); // The parameter you pass here is the function that control
// will pass back to once the called function is done.
}
public void callWebService(DownloadStringCompletedEventHandler callback){
//Calls web service and does some other operations
}
And finaly the question. As you can see above I have the 2 classes, class1 calls a function in class2. That function calls another function also in class2 that calls a webservice. Once that web serivce is done control flow passes back to whatever function you passes in the function call.
But that means you're stuck to one class since the callback function should be in the same class. So the question is, how can I pass a function in another class to be the callback function?
Hope all this makes sense, please don't hesitate asking anything to clear things up a bit more. Thanks!
You can modify the Service class and pass MyClass1's method to it.For e.g In the below code , the function ServiceCallComplete is passed as a parameter to the Service class constructor.
The function can be saved as either Action or Func delegate type(depending on your callback function definition).Once the service job is done ,calling the delegate(_callBack()) will invoke the callback function on MyClass1.
public class MyClass1
{
//The callback Function
public void ServiceCallComplete()
{
Console.WriteLine("Function returned.");
}
}
public class Service
{
//delegate to store the callback function.
private readonly Action _callBack;
public Service(Action callBack)
{
//store the callback function
_callBack = callBack;
}
public void Method()
{
//long running operation
.
.
//Invoke the callback
_callBack();
}
}
MyClass1 obj = new MyClass1();
Service svc = new Service(obj.ServiceCallComplete);
svc.Method();
Instead of passing a delegate, use an event:
class MyClass1
{
public MyClass1()
{
var c2 = new MyClass2();
c2.ActionwebServiceCalled += MyCallBack; //register for the event
c2.CallWebService();
}
public void MyCallBack(object sender, DownloadStringCompletedEventArgs e)
{
Console.Write("Function returned!");
}
}
class MyClass2
{
public event DownloadStringCompletedEventHandler ActionwebServiceCalled;
public void CallWebService()
{
DownloadStringCompletedEventArgs e = null;
//Calls web service and does some other operations...
var handler = ActionwebServiceCalled;
if (handler != null)
handler(this, e);
}
}
Having said that, you'd might want to introduce asynchrony to the web service call, in which case the Task-based Asynchronous Pattern (TAP) is the way to go, provided that you have .NET 4 (or Rx). For .NET 3.5 and lower, you'll want to follow the Asynchronous Programming Model (APM).
Related
Hi all new to C# so apologies upfront
I am trying to create an handle in a program to retrieve the string/text and event from this public function in this (websocketwrapper) class.
I have part of the class in question here:
public WebSocketWrapper OnMessage(Action<string, WebSocketWrapper> onMessage)
{
_onMessage = onMessage;
return this;
}
note: _onMessage is declared in the class as:
private Action<string, WebSocketWrapper> _onMessage;
I understand how delegates work and in the process of learning how to use them in actions and event handling but can't work out how to create away to retrieve the result of the above method.
That pattern is typically used for you to add your own callback, i.e.
server.OnMessage((s, wrapper) => {
Console.WriteLine($"received: {s}");
});
So: whenever a message is received, your callback is invoked and provides the value as s that is only defined inside the callback lambda. You could also write this as:
server.OnMessage(ProcessMessage);
...
void ProcessMessage(string s, WebSocketWrapper wrapper)
{
Console.WriteLine($"received: {s}");
}
where now the ProcessMessage method will be invoked whenever a message is received.
I am completely new to events in c# and this is what I want to do:
I have two methods:
OpenPage1();
OpenPage2();
When either of these methods is called, I want a third method named as PerformSomeTask() to be called.
I believe that this can be done by event handling. Could anyone tell me how to do this?
All you have to do in your class is to add an event with a correct eventHandler (Action in your example). The eventHandler should correspond the method that will subscribe to this event.
Then you fire the event from the openPage Methods.
You must check for null in case no one subscribed to this event.
public class Foo
{
public event Action theEvent;
public void OpenPage1()
{
if (theEvent != null)
theEvent();
}
public void OpenPage2()
{
if (theEvent != null)
theEvent();
}
}
public class Bar
{
public int Counter { get; set; }
public void PerformSomeTask()
{
Counter++;
}
}
And here's a test that you can run to see it all together:
[TestMethod]
public void TestMethod1()
{
var foo = new Foo();
var bar = new Bar();
foo.theEvent += bar.PerformSomeTask;
foo.OpenPage1();
foo.OpenPage2();
Assert.AreEqual(2, bar.Counter);
}
Events is a big part of C#.
To be simple, you need first a delegate that describe type of called method. In your example, PerformSomeTask is void and take no parameters.
So declare in your class
public delegate void PerformSomeTask();
Then, you need to declare event, which is the member that will called to launch your function
public event PerformSomeTask OnPerformSomeTask;
On your both methods, OpenPage1 and OpenPage2, you need to check if someone subscribe to your event, if yes, call it.
if(OnPerformSomeTask != null)
OnPerformSomeTask();
This will launch every method that subscribe to your event. Subscribers can be multiple.
To subscribe, just do it like this :
YourClass.OnPerformSomeTask += MyVoidMethod;
[...]
public void MyVoidMethod() { DoSomething(); [...] }
Your void method will be called everytime your run OpenPage1 and OpenPage2
If you need some parameters, juste change your delegate to proceed.
public delegate void PerformSomeTask(string myParam);
Then, your methods will have this parameter as standard function parameter (call your event with your value to pass it as parameter to every subscriber function).
In Dustin Campbell's answer in question Return a value from a Event — is there a Good Practice for this? it is stated that instead of returning data from an event handler, we can have a writable property on a set of custom EventArgs that is passed to the event similar to Cancel property of the WinForms FormClosing event.
How do I provide feedback to event caller using properties in EventArgs?
My specific scenario is that there is a Controller class that does Job A and there are many classes requesting the Job A to be done. Thus, the controller is subscribed to this event on all classes.
I want to give some feedback to the caller that the job is done. The tricky part is that those classes are module-like and controller doesn't know anything about them.
My though is to include that writable property to the delegate of the event in order for the controller to give feedback through it. This property could somehow be invoked using reflection, which is fine in my scenario.
you cannot define properties for delegates.
Also you do not need reflection for such a mechanism.
What you want to do is to define your "return"-properties in the EventArgs-derived class.
A simple such class would be:
public class JobEventArgs : EventArgs {
public bool Done { get; set; }
}
Now you can declare your event in the class as
public event EventHandler<JobEventArgs> Job;
Usage in the method which handles the event:
public void DoJob(object s, JobEventArgs args) {
// do stuff
args.Done = true;
}
and in the event invoking code:
public void FireJobEvent() {
var args = new JobEventArgs();
this.Job(this, args);
if(!args.Done) {
// the job was not handled
}
}
But frankly it rather seems like you want to do a job asynchronously with a notification when it finishes.
Which would result in syntax like..
class Module {
public void JobCompleted(IAsyncResult r) {
if(!r.IsCompleted)
return;
Console.WriteLine("The job has finished.");
}
public void ExecuteJob() {
var job = new EventArgs<JobEventArgs>((s, a) => { this.controller.JobA(); });
job.BeginInvoke(null, null,
r =>
{
this.JobCompleted(r);
if(r.IsCompleted)
job.EndInvoke(r);
}, null);
}
}
I am using an external class to open up a connection to a remote application. This class receives the data from the remote application which is handled via a handler.
To this handler I have added several checks to parse the data in separate methods. However I am now stuck at the point where I need to access the object again which triggered the event to call a method on it. I am sure this is a pretty basic question but I am just starting with OOP.
public static void Main(string[] args) {
IBattleNET b = new BattlEyeClient(loginCredentials);
b.MessageReceivedEvent += HandleMessage;
b.Connect();
}
private static void HandleMessage(BattlEyeMessageEventArgs args) {
//call a method to analyze data parse
PlayerList(args.Message);
}
private static void parsePlayerList(string playerList) {
// At this point I need to access the object b again to to call a method
}
Modify the handler to pass over the object:
b.MessageRecievedEvent += (e) => HandleMessage(b, e);
....
private static void HandleMessage(IBattleNet b, BattleMessageEventArgs args) {
....
The lambda expression stores the args as 'e', then calls HandleMessage by passing it both the object and 'e'.
The convention Pickles presented is better practice, however, if you have access to and can change the event itself inside of IBattleNET.
Typically events use delegates that have two parameters in their signature. An object "source" parameter to represent the sender and an "args" parameter to represent the event args.
If you have access to the MessageReceivedEvent you should change the delegate to include an "object" parameter to represent the sender. Then your HandleMessage method would look like this:
private static void HandleMessage(object sender, BatlEyeMessageEventArgs args)
{
var battleNet = sender as IBattleNet;
if (battleNet == null)
return;
battleNet.Foo();
PlayerList(args.Message);
}
Since your incoming method is static, you are presented with some challenges, particularly what happens when multiple messages arrive in a very close period of time? If you store the information that you want to reuse later, it could easily be overwritten by the next message that is received.
In cases like this, I generally create a new class that is responsible for the parsing and processing of the incoming message and, in the event handler, create a new instance of that class passing the event arguments to the constructor.
From that point forward, all processing of the message occurs in the class instance.
For example, you could have a class like this that stores the message, validates it, and then later performs some parsing on it::
public class PlayerListEvent
{
private string m_sMessage;
public PlayerListEvent(String sMessage)
{
m_sMessage = sMessage;
}
public Boolean MessageIsValid()
{
// Validate the incoming message
return true;
}
public void ParseMessage() {
// Perform the message parsing
}
}
You could store all incoming messages in a list (or class or some other storage mechanism) so that they can be processed as needed:
private static System.Collections.Generic.List<PlayerListEvent> m_cReceivedMessages = new System.Collections.Generic.List<PlayerListEvent>();
Then, when your message arrives, you can create a new instance of the class and, if it's valid, add it to the queue for processing later (you could do just about anything here including firing a background worker process to handle the incoming message, etc):
private static void HandleMessage(BattlEyeMessageEventArgs args) {
//call a method to analyze data parse
var oPlayerListEvent = new PlayerListEvent(args.Message);
if (oPlayerListEvent.MessageIsValid()) {
lock (m_cReceivedMessages) {
m_cReceivedMessages.Add(oPlayerListEvent);
}
}
}
I have a class that is a "manager" sort of class. One of it's functions is to signal that the long running process of the class should shut down. It does this by setting a boolean called "IsStopping" in class.
public class Foo
{
bool isStoping
void DoWork() {
while (!isStopping)
{
// do work...
}
}
}
Now, DoWork() was a gigantic function, and I decided to refactor it out and as part of the process broke some of it into other classes. The problem is, Some of these classes also have long running functions that need to check if isStopping is true.
public class Foo
{
bool isStoping
void DoWork() {
while (!isStopping)
{
MoreWork mw = new MoreWork()
mw.DoMoreWork() // possibly long running
// do work...
}
}
}
What are my options here?
I have considered passing isStopping by reference, which I don't really like because it requires there to be an outside object. I would prefer to make the additional classes as stand alone and dependancy free as possible.
I have also considered making isStopping a property, and then then having it call an event that the inner classes could be subscribed to, but this seems overly complex.
Another option was to create a "Process Cancelation Token" class, similar to what .net 4 Tasks use, then that token be passed to those classes.
How have you handled this situation?
EDIT:
Also consider that MoreWork might have a EvenMoreWork object that it instantiates and calls a potentially long running method on... and so on. I guess what i'm looking for is a way to be able to signal an arbitrary number of objects down a call tree to tell them to stop what they're doing and clean up and return.
EDIT2:
Thanks for the responses so far. Seems like there's no real consensus on methods to use, and everyone has a different opinion. Seems like this should be a design pattern...
You can go two ways here:
1) The solution you've already outlined: pass a signaling mechanism to your subordinate objects: a bool (by ref), the parent object itself cloaked in an interface (Foo: IController in the example below), or something else. The child objects check the signal as needed.
// Either in the MoreWork constructor
public MoreWork(IController controller) {
this.controller = controller;
}
// Or in DoMoreWork, depending on your preferences
public void DoMoreWork(IController controller) {
do {
// More work here
} while (!controller.IsStopping);
}
2) Turn it around and use the observer pattern - which will let you decouple your subordinate objects from the parent. If I were doing it by hand (instead of using events), I'd modify my subordinate classes to implement an IStoppable interface, and make my manager class tell them when to stop:
public interface IStoppable {
void Stop();
}
public class MoreWork: IStoppable {
bool isStopping = false;
public void Stop() { isStopping = true; }
public void DoMoreWork() {
do {
// More work here
} while (!isStopping);
}
}
Foo maintains a list of its stoppables and in its own stop method, stops them all:
public void Stop() {
this.isStopping = true;
foreach(IStoppable stoppable in stoppables) {
stoppable.Stop();
}
}
I think firing an event that your subclasses subscribe to makes sense.
You could create a Cancel() method on your manager class, and on each of your other worker classes. Base it on an interface.
The manager class, or classes that instantiate other worker classes, would have to propagate the Cancel() call to the objects they are composed of.
The deepest nested classes would then just set an internal _isStopping bool to false and your long-running tasks would check for that.
Alternatively, you could maybe create a context of some sort that all the classes know about and where they can check for a canceled flag.
Another option was to create a
"Process Cancelation Token" class,
similar to what .net 4 Tasks use, then
that token be passed to those classes.
I am not familiar with this, but if it is basically an object with a bool property flag, and that you pass into each class, then this seems like the cleanest way to me. Then you could make an abstract base class that has a constructor that takes this in and sets it to a private member variable. Then your process loops can just check that for cancellation.
Obviously you will have to keep a reference to this object you have passed into your workers so that it's bool flag can be set on it from your UI.
Your nested types could accept a delegate (or expose an event) to check for a cancel condition. Your manager then supplies a delegate to the nested types that checks its own "shouldStop" boolean. This way, the only dependency is of the ManagerType on the NestedType, which you already had anyway.
class NestedType
{
// note: the argument of Predicate<T> is not used,
// you could create a new delegate type that accepts no arguments
// and returns T
public Predicate<bool> ShouldStop = delegate() { return false; };
public void DoWork()
{
while (!this.ShouldStop(false))
{
// do work here
}
}
}
class ManagerType
{
private bool shouldStop = false;
private bool checkShouldStop(bool ignored)
{
return shouldStop;
}
public void ManageStuff()
{
NestedType nestedType = new NestedType();
nestedType.ShouldStop = checkShouldStop;
nestedType.DoWork();
}
}
You could abstract this behavior into an interface if you really wanted to.
interface IStoppable
{
Predicate<bool> ShouldStop;
}
Also, rather than just check a boolean, you could have the "stop" mechanism be throwing an exception. In the manager's checkShouldStop method, it could simply throw an OperationCanceledException:
class NestedType
{
public MethodInvoker Stop = delegate() { };
public void DoWork()
{
while (true)
{
Stop();
// do work here
}
}
}
class ManagerType
{
private bool shouldStop = false;
private void checkShouldStop()
{
if (this.shouldStop) { throw new OperationCanceledException(); }
}
public void ManageStuff()
{
NestedType nestedType = new NestedType();
nestedType.Stop = checkShouldStop;
nestedType.DoWork();
}
}
I've used this technique before and find it very effective.
Litter your code with statements like this wherever it is most sensible to check the stop flag:
if(isStopping) { throw new OperationCanceledException(); }
Catch OperationCanceledException right at the top level.
There is no real performance penalty for this because (a) it won't happen very often, and (b) when it does happen, it only happens once.
This method also works well in conjunction with a WinForms BackgroundWorker component. The worker will automatically catch a thrown exception in the worker thread and marshal it back to the UI thread. You just have to check the type of the e.Error property, e.g.:
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if(e.Error == null) {
// Finished
} else if(e.Error is OperationCanceledException) {
// Cancelled
} else {
// Genuine error - maybe display some UI?
}
}
You can flatten your call stack by turning each DoWork() call into a command using the Command pattern. At the top level, you maintain a queue of commands to perform (or a stack, depending on how your commands interact with each other). "Calling" a function is translated to enqueuing a new command onto the queue. Then, between processing each command, you can check whether or not to cancel. Like:
void DoWork() {
var commands = new Queue<ICommand>();
commands.Enqueue(new MoreWorkCommand());
while (!isStopping && !commands.IsEmpty)
{
commands.Deque().Perform(commands);
}
}
public class MoreWorkCommand : ICommand {
public void Perform(Queue<ICommand> commands) {
commands.Enqueue(new DoMoreWorkCommand());
}
}
Basically, by turning the low-level callstack into a data structure you control, you have the ability to check stuff between each "call", pause, resume, cancel, etc..