adding event to another class after completion of a method - c#

Suppose I have two classes - one that is provided to me (but suppose I am not allowed to change it as it is maintained by someone else), and one that I control and can change.
// Class A is provided to me by someone else, and suppose I can't modify it
public class A
{
public A()
{
...
}
public void DoSomethingInA()
{
...
}
}
// Class B is what I control
public class B
{
public A MyClassAInstance;
public B(A myClassAInstance)
{
MyClassAInstance = myClassAInstance;
// *** HERE IS WHERE I NEED HELP
// NEED TO WRITE AN EVENT / EVENT HANDLER, WITH / WITHOUT REFLECTION
// THAT RUNS DoSomethingInB WHENEVER MyClassAInstance's DoSomethingInA
// METHOD IS CALLED (AND COMPLETED)
}
public void DoSomethingInB()
{
...
}
}
How can I define a Event / EventHandler in class B that kicks off its DoSomethingInB method whenever the class A instance MyClassAInstance's method DoSomethingInA is called (and completed).
I tried lot of options, but none seem to work.
For instance, I tried:
public class B
{
public A MyClassAInstance;
public B(A myClassAInstance)
{
MyClassAInstance = myClassAInstance;
var eventInfo = GetType().GetEvent("MyEvent");
var methodInfo = myClassAInstance.GetType().GetMethod("DoSomethingInA");
Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, myClassAInstance, methodInfo);
eventInfo.AddEventHandler(this, handler);
MyEvent += DoSomethingInB;
}
public event EventHandler MyEvent;
public void DoSomethingInB()
{
...
}
}
But this doesn't work.
Any suggestions or help would be greatly appreciated.

Related

C# Call function from another class

I think my question is best descirbed by a code snippet:
class A
{
public void FunctionToBeCalled();
}
class B
{
public void FunctionToBeCalledAfter();
}
Now, after a FunctionToBeCalledAfter() call, FunctionToBeCalled() needs to "know" it must be called. B cannot have an A member, but A can have a B member. Is there any way this can be implemented in C#?
Why i need this:
Class A is Application level on OSI stack. Classes B and C(unmentioned before) are Transport Level. C makes calls to FunctionToBeCalledAfter, and after this FunctionToBeCalled needs to be called. But sincer A is a higher level, B and C cannot depend(have a member A), i don't know how to call FunctionToBeCalled.
I see 2 ways to accomplish this, one easier but (arguably) less elegant, one a little more involved but (arguably) more elegant
The less elegant solution: Singleton
A Singleton pattern enforces that there can only ever be one instance of a class at any given time, this seems to line up with your description of A (which from here on out I'll call Foo, and I'll be calling B Bar). So let's implement it:
public class Foo
{
private static Foo _instance;
public static Foo Instance => _instance ?? (_instance = new Foo());
// Private constructor so no one else can instantiate Foo
private Foo() { }
public void FunctionToBeCalled() { /* your code here */ }
}
public class Bar
{
public void FunctionToBeCalledAfter()
{
// Your existing code here
Foo.Instance.FunctionToBeCalled();
}
}
Now, the problem here is if your requirements ever change and you need multiple Foos, that'll be quite a refactor to implement it. Another (larger) downside is that we explicitly reference (i.e depend on) Foo, which isn't great and a problem if Bar is inside a project/ library that cannot directly reference Foo. Luckily solution 2 fixes those problems:
The more elegant solution: Events
public class Foo
{
// We don't need Foo to be a singleton anymore
public void FunctionToBeCalled() { /* Your code here */ }
}
public class Bar
{
public delegate void FunctionToBeCalledAfterEventHandler();
public event FunctionToBecalledAfterEventHandler FunctionToBeCalledAfterEvent;
public void FunctionToBeCalledAfter()
{
// Your existing code here
OnFunctionToBeCalledAfterEvent(); // Fire the event
}
private void OnFunctionToBeCalledAfterEvent()
{
FunctionToBeCalledEvent?.Invoke();
}
}
Now, everywhere where you're creating an instance of Bar you need to have a reference to Foo and subscribe to the event like so:
// foo = instance of class Foo
var bar = new Bar();
// The compiler is smart enough to find out that 'FunctionToBeCalledAfterEvent'
// has the same signature as 'FunctionToBeCalledAfterEvent' and can call it directly
// If this just so happens to not be case, see second way to subscribe to events
bar.FunctionToBeCalledAfterEvent += foo.FunctionToBeCalled;
// Or
bar.FunctionToBeCalledAfterEvent += () => foo.FunctionToBeCalled();
Events are great
Class B can have an event that other parties can handle. At the end of B.FunctionToBeCalledAfter this event would be invoked. Anyone who registered for this event would then be notified. Usual boilerplate code involves one virtual method that invokes one event. It's the standard way of adding events. If there is no need for additional data in the event then EventArgs is used. If additional data is needed then you could replace EventArgs with EventArgs<YourData>, or as an alternative, introduce a class XxxArgs derived from EventArgs with this additional data.
Class B
{
public event EventHandler FinishedFunctionToBeCalledAfter;
protected virtual void OnFinishedFunctionToBeCalledAfter(EventArgs e)
{
EventHandler handler = FinishedFunctionToBeCalledAfter;
handler?.Invoke(this, e);
}
public void FunctionToBeCalledAfter()
{
...
OnFinishedFunctionToBeCalledAfter(EventArgs.Empty);
}
}
Now when class A gets a hold of an object of class B it would add its event handler to it:
class A
{
public void FunctionToBeCalled();
public void FinishedFunctionToBeCalledAfter(object source, EventArgs e);
public void IntroduceObject(B b)
{
b.FinishedFunctionToBeCalledAfter += FinishedFunctionToBeCalledAfter;
}
}
When this object b of class B should end its life class A must know about it so that it can remove its event handler:
b.FinishedFunctionToBeCalledAfter -= FinishedFunctionToBeCalledAfter;

CollectionChanged Event is not firing on a static ObservableCollection

In one class I'm adding objects to my ObservableCollection. And in another class, I'm doing stuff with my added object and then delete it from the collection.
Those two classes cannot communicate with each other, so I decided to go for static collection (I only have access to the class definition for some reason)
In my first class, all elements are added properly (I checked the Count property), in the second class I subscribe to the CollectionChanged event. However, the event is not raising. I think it's because of the statickeyword, but I'm not sure.
Here is a code sample:
static public class A
{
public static ObservableCollection<object> MyCollection = new ObservableCollection<object>();
}
public class B
{
public B()
{
A.MyCollection.CollectionChanged += Func_CollectionChanged;
}
void Func_CollectionChanged(...)
{
//Stuff
}
}
public class C
{
public void func()
{
A.MyCollection.Add(object);
}
}
Here it works fine for me:
class Program
{
static void Main(string[] args)
{
B obj = new B();
}
}
public class A
{
public static ObservableCollection<object> MyCollection = new ObservableCollection<object>();
}
public class B
{
public B()
{
A.MyCollection.CollectionChanged += Func_CollectionChanged;
A.MyCollection.Add(1);
}
private void Func_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
// do some stuff here
}
}
by using A.MyCollection.CollectionChangedline you are creating an EventHandler to handle the the collection change event. it fires when ever any changes(add/update/delete) made in the collection. since it is a delegate you are creating you have to specify the sender who own the event and the type of arguments(What it going to handle), in-order to get proper reporting of published event
Updates
You just look into your code. the instance of class b is not yet created, the constructor of this class will automatically invoked only when the new instance of the class is created. You are creating the Event handler inside the constructor of class b. So it is not yet published any event. that is the reason for the collection_Change event is not triggering in your code snippet.
Hence your Definition for class C will be like the following to register the event :
public class C
{
B obj = new B();
public void func()
{
A.MyCollection.Add(1);
}
}

How to define a new class that inherits from Delegate

is there anyway to do something similar to what ive got bellow.
What im trying to do is to invoke a list of delegates at a specific point in time and keep track of them, and for the sake of keeping code clean, keep the delegates to be invoked in a list of some sort.
public interface IServiceStatusDelegate
{
object DynamicInvoke(object[] args)
}
public class ServiceStatusDelegate
: Delegate, IServiceStatusDelegate
{
}
public class MyServiceStatusCheckedDelegate
: ServiceStatusDelgate
{
}
public class MyServiceStatusChangedDelegate
: ServiceStatusDelgate
{
}
public class MyClass
{
public ServiceStatusDelgate[] listOfDelegatesToInvoke;
public void InvokeRequiredDelegates()
{
foreach(ServiceStatusDelegate delegateToInvoke in this.listOfDelegatesToInvoke)
delegateToInvoke.DynamicInvoke(new object[]{this, DateTime.Now});
}
}
You don't need a list of delegates... any delegate you create in c# is going to be multicast, so all you need is any delegate, and you can combine them with +. Just invoke it and all targets will be reached. For example:
Action target = null;
...
target += Method1;
...
target += Method2;
...
if(target != null) target(); // calls Method1 and Method2
This could (although it isn't necessary for it to stand) be implemented via an event which will make the convention very obvious the caller.

Difference between assigning an Action<T> method and subscribing to Action<T> event

Lets say I have the below code. What is the difference between assigning the actions directly and subscribing to an event?
//Action directly assigned
public class ClassA
{
public Action<string> OnAdd;
private void SomethingHappened()
{
OnAdd("It Happened");
}
}
public class ClassB
{
public ClassB()
{
var myClass = new ClassA();
myClass.OnAdd = Add;
}
private void Add(string Input)
{
//do something
}
}
//Event handlers
public class ClassA
{
public event Action<string> OnAdd;
private void SomethingHappened()
{
if (OnAdd != null)
OnAdd("It Happened"); //Should it be OnAdd.Invoke("It Happened") ???????
}
}
public class ClassB
{
public ClassB()
{
var myClass = new ClassA();
myClass.OnAdd += Add;
}
private void Add(string Input)
{
//do something
}
}
(As an aside, it's hard to explain things when you've used the same type names twice.)
When you use a public field, clients can not only subscribe to events - they can also completely remove other event handlers by assigning instead of adding:
myClass.OnAdd = Add;
They can also invoke the handler directly:
myClass.OnAdd("foo");
Both of these violate the normal pub/sub pattern, where the various subscribers are isolated from one another. Subscribers don't get to overwrite each other's subscriptions (only add or remove their own) and they don't get to raise the event themselves.
For more on events and delegates, see my article on the topic.
You can assign more than one delegates to one event (thus the += operator).
An Event acts like a wrapper around a Delegate to offer protection from reassigning/removing as John has pointed out. I found this quite a good read.

Events returning values as methods, is it correct?

In my app, I wanted to let class B get some information from class A but as A instantionates B, B has no reference to A (intentionally).
I have never used events for that purpose so I am not sure whether its correct, but it works:
class A
{
public delegate bool GetFromB();
public event GetFromB GetDataFromB;
...
//get data from B without having an access to it
bool Result=GetDataFromB();
}
class B
{
A a=new A();
A.GetDataFromB=new A.GetFromB(DO_THAT);
public bool DO_THAT()
{
...
return true; //and that is it, it will return to event caller
}
}
It'll certainly work, and that approach is used in a few places in the core framework - AssemblyResolve etc. Alternative approaches here:
if it is used by a method, pass it into the method as a callback delegate. Same approach, but simply not exposed as an event
ditto, but with an interface
but it'll work that way. It isn't unheard of. Code tweaks, though:
A a=new A();
a.GetDataFromB=+new A.GetFromB(DO_THAT);
you subscribe on the instance (unless it is static), and need +=, not =.
Also: consider using Func<bool> rather than declaring your own delegate type.
Don't do that. Events implies that multiple listeners can be used, and it looks like you are not handling return values from multiple listeners. You can do that by traversing myevent.GetInvocationList() and invoke each listener separately.
Use a simple delegate instead:
class A
{
public delegate bool GetFromB();
public GetFromB GetDataFromB { get; set; }
}
The other standard way is to have event arguments that provide a property for return value.
class MyEventArgs : EventArgs
{
public bool ReturnValue {get; set; }
// and something more here.
}
public class A
{
public event EventHandler<MyEventArgs> MyEvent;
}
As you wrote, A currently instanciates B so, you should not change this by creating an instance of A in B.
If B needs several different data from A, you can let A realize some IBNeededData interface. If B needs only one call on A, the straight forward solution would be a callback method.
Edit
Here's a sample for the callback. (Hope you are fine with the lambda expression to provide the data from A.)
[TestClass]
public class UnitTest1 {
class A {
public void DoWork() {
B b = new B();
//b.GetData = () => "Some data";
Func<string> callback = new Func<string>(this.GetBData);
b.GetData = callback;
b.DoBWork();
}
private string GetBData() {
return "Some data";
}
}
class B {
public Func<string> GetData { get; set; }
public void DoBWork() {
string data = GetData();
Console.WriteLine("Working with {0}", data);
}
}
[TestMethod]
public void TestMethod1() {
A a = new A();
a.DoWork();
}
}

Categories

Resources