Im fully aware of the "problem" with static event handlers from a GC perspective so i'm not looking for advice on "DONT use static events" or anything like that, in my scenario this isnt a concern.
I have a static class which has an event declared
public static event EventHandler<MyEventArgs> FilePickedUpFromStorage;
i have a client service that subscribes to this event and im wanting to Mock/test the static event being fired with a fake MyEventArgs to assert the handling works as specified, at the client. Straightforwards stuff.... the problem i have is that this event is static on a static class. im looking for some solid guidance on the best approach to dealing with this, if anyone can offer any help. Changing the static event is not an option, wrapping it or any other magic is...
Thanks!
Since you specifically states that it is not an option to change the event from static to instance, you could take a look at TypeMock Isolator. It is a mocking framework that works by rewriting IL code necessary to mock stuff that could not otherwise be mocked. It is not the best solution IMO, but it will help you do want you want in this situation without changing the code.
You could keep the static event for "legacy compatibility" and provide a better structure for new (and testable) code.
// legacy
public static class OldClass
{
public static event EventHandler<MyEventArgs> FilePickedUpFromStorage;
}
// new interface for testability
public interface IBraveNewWorld
{
event EventHandler<MyEventArgs> FilePickedUpFromStorage;
}
// new implementation
public class BraveNewWorld : IBraveNewWorld
{
public event EventHandler<MyEventArgs> FilePickedUpFromStorage;
public BraveNewWorld()
{
// MyHandler forwards the event
OldClass.FilePickedUpFromStorage += MyHandler;
}
}
// new testable user of the event.
public class TestableClass
{
// here you can pass a mock or just an instance of BraveNewWorld
public TestableClass(IBraveNewWorld x)
{
}
}
You are testing your class's response to receiving an event. So presumably you are concerned about the bahviour of a method on your class which receives the event
public void OnHandler1(object sender, MyEventArgs e)
So in your tests don't you just call that method directly? You might need to mock the sender object, but presumbly he is of a known type because you're casting him to use him, so you know what to mock.
In other words for testing your class you may not actually need the real source of events at all.
Related
What alternative can one use to avoid exposing both events and an interface.
I have a class that has a determined life cycle: created, modified, ...
clients mainly GUIs need to hook up into the life cycle of that class so the simplest way to do it is to expose events, at the same time I need to move some responsibilities -that happen during the life cycle- out of the class so I came up with this solution:
Interface ILifeCycle
{
void OnCreated(...);
void OnModified(...);
// ...
}
classA
{
private ILifeCycle lifeCycle;
/// ...
public event EventHandler Created(object sender, EventArgs args);
public event EventHandler Modified(object sender, EventArgs args);
/// ...
protected void OnCreated()
{
lifeCycle.OnCreated(...);
if(Created!=null)
Created(this,EventArgs.Empty);
}
protected void OnModified()
{
lifeCycle.OnModified(...);
if(Modified!=null)
Modified(this,EventArgs.Empty);
}
/// ...
}
Doing this I can inject a Logger that implements ILifeCycle, and so move the logging responsibility to its own class,
but it feels like it's going to be a lot of repetition.
What clean alternatives would you recommend to achieve this?
In general Interface and Events/Delegates are used for two very different kinds of approach. Lets describe them each first -
Interface: The main purpose of interface is that it enforces some functionality to all implementations of that interface. And whenever you implement it in a subclass, you override the implementation of the super class. For example -
interface IA
{
void test();
}
class A : IA
{
public void test(){
}
}
class B : A
{
public void test(){
//you can only go up by calling base.test(), but cannot move down, because you do not know whether there is an implementation down the tree or not. So you cannot call it.
}
}
class C : B
{
public void test(){
//you can only go up by calling base.test(), but cannot move down, because you do not know whether there is an implementation down the tree or not. So you cannot call it.
}
}
As you can see, with interface you can only look back but cannot look forward and assume there will be any more implementations.
Events: Events are created for a different purpose. lets just say you want to give the developers some facility to rely on some activities and do some other activities based on that activities and changes, and most importantly they will be implement this in future. The events will not depend on your implementation, they will just subscribe to it and do something based on that. Whether they exists or not, your own implementation does not change or the behavior of your own code does not changes based on them. In other words, you can only move down the tree. The base class captured the event and then propagates them down the tree.
These are the usual uses of Interface and Events and they are meant to be used that way. But its not completely impossible to code such that it will entirely depend on interface and vice versa, i.e. code entirely dependent on events but that is not the way they are meant to be.
In This Case: In your case, I am thinking you are trying to achieve a modular system that will not depend on each other but again subscribe to events. There are other architectures and patterns for this, specially IOC containers will be a very helpful for you, that will entirely be interface dependent, you will not need events. Some .net IOC containers are AutoFac, Castle.Windsor, MEF
I myself, like MEF the most, here is a post on MEF that I wrote few years back, shows you how you can inject run-time handlers inside a container -
http://mahmudulislam.me/2012/04/20/1a-managed-extensibility-framework-introduction/
BTW, article is a bit old, I am working on updating this one.
Solution with IOC: I am giving a probable solution with MEF -
Interface ILifeCycle
{
void OnCreated(...);
void OnModified(...);
...
}
[Export(typeof(ILifeCycle))] //export our classes for injection
classB : ILifeCycle{
public void OnCreated(...)
{
....
}
public void OnModified(...){
}
}
[Export(typeof(ILifeCycle))] //export our classes for injection
classC : ILifeCycle{
public void OnCreated(...)
{
....
}
public void OnModified(...){
}
}
classA
{
[ImportMany] //get all exported classes for injection
private IList<ILifeCycle> _observers;
protecetd void OnCreated()
{
//use MEF to build composition and then do the following
foreach(var o in _observers){
o.OnCreated(...);
}
}
protecetd void OnModified()
{
//use MEF to build composition and then do the following
foreach(var o in _observers){
o.OnModified(...);
}
}
...
}
This is a very basic solution. But in your case you might wanna make use of asynchronous programming. Because there is very big difference between Events and Interfaces. By default, events handlers are call in a separate thread and thus it does not halt the caller, but interface implement will hang the caller until the method finishes. So make sure you use asynchronous programming to not block your main process.
Asynchronous Programming with Async and Await (C# and Visual Basic)
I'm not sure I understood you well but I think you worry about repetitions in different types implementing ILifeCycle. So, you can take advantage of inheritance:
abstract class LifeCycleBase
{
public void OnCreated(...)
{
.....
}
public void OnModified(...);
{
.....
}
...
}
class LifeCycleLoger : LifeCycleBase
{
public void OnCreated(...)
{
....
base.OnCreate();
}
....
}
class Program
{
static void Main(string[] args)
{
B b = new B();
b.Run();
Console.Read();
}
}
class A
{
public event Action onChanged;
public void Raise()
{
if (onChanged != null)
onChanged();
}
}
class B
{
public void Run()
{
A a = new A();
a.onChanged += a_onChanged;
a.Raise();
}
private void a_onChanged()
{
Console.WriteLine("Wow! Invoked");
}
}
I am not able to figure out the Valid points which can justify that I broke encapsulation or may be otherwise. As per my understanding I am breaking encapsulation as a private method is getting called from another class, Is this enough for justifying that I broke on the laws of OOP. Need to gather some more inner concepts and descrption for the code above.
This really depends on why do you have a Raise method in class A.
If it there solely for enabling the access to a private member, then the answer would be: yes, your encapsulation has been compromised.
The onChanged event should occur when something has changed and not when some external class decides it should.
However, if this is only a simple snapshot for making a point, and the Raise event is a method that is triggering the event as a side effect to an action taken (something like changing text in a Textbox and then triggering onTextChanged) than your encapsulation is still in tact.
Note:
I am breaking encapsulation as a private method is getting called
from another class
From Wikipedia:
Encapsulation is used to hide the values or state of a structured data
object inside a class, preventing unauthorized parties' direct access
to them. Publicly accessible methods are generally provided in the
class (so-called getters and setters) to access the values, and other
client classes call these methods to retrieve and modify the values
within the object.
It is OK for the private method to be called from a public one. How else would it be called? It is up to you, the programmer, to get your methods logic straight and make sure that they call the appropriate methods.
You didn't break encapulation on class B, since instances of B only modify themselves, but yes, you broke encapsulation on class A. Anything that has a reference to an instance of A can raise the onChanged event.
No, you did not break encapsulation and a private method is getting called from another class is not true in this case. Class B creates it's own A and calls it's Raise method which raises an onChanged event.
You are registering to this event from B therefore it's completely fine.
I am new to C# so this is probably me just not understanding something fundamental or missing out on some feature of the language. I've searched online but all the examples I seem to find have everything all in one class (in other words, they define the event as well as the method that executes when the event is triggered), which is not what I want.
For my scenario I'd like to define an interface of listener methods that can accept some custom parameters (this would be my own EventArgs right?) that provide instructions. Lets pretend its for a car, so I have methods named:
Start(MyCustomParameters par)
Accelerate(MyCustomParameters par)
Decelerate(MyCustomParameters par)
and then I want to be able to create classes that provide the actual implementation of these methods.
completely separate from all this, I have a single class that executes periodically based on an external process and I want it to be responsible for triggering these events (when the car starts and accelerates etc).
That's the basics of what I'm trying to get working but no luck so far. Also, one follow-up question. If my listener-implementation class needs to maintain any kind of state from a given call, how best to do that (e.g. say that when Accelerate is called it wants to be able to return the speed that it accelearted to back to the invoker of the event - e.g. 80 kph)
hope you can help SO, thank you very much
here is a simple example of event/listener in c# :
//your custom parameters class
public class MyCustomParameters
{
//whatever you want here...
}
//the event trigger
public class EventTrigger
{
//declaration of the delegate type
public delegate void AccelerationDelegate(MyCustomParameters parameters);
//declaration of the event
public event AccelerationDelegate Accelerate;
//the method you call to trigger the event
private void OnAccelerate(MyCustomParameters parameters)
{
//actual triggering of the events
if (Accelerate != null)
Accelerate(parameters);
}
}
//the listener
public class Listener
{
public Listener(EventTrigger trigger)
{
//the long way to subscribe to the event (to understand you create a delegate)
trigger.Accelerate += new EventTrigger.AccelerationDelegate(trigger_Accelerate);
//a shorter way to subscribe to the event which is equivalent to the statement above
trigger.Accelerate += trigger_Accelerate;
}
void trigger_Accelerate(MyCustomParameters parameters)
{
//implement event handling here
}
}
I hope it helps.
Consider we have a class with event declared:
public class FooBar
{
public event EventHandler FooBarEvent;
}
Despite of "publicness" of the event, we cannot call FooBarEvent.Invoke from outside.
This is overcame by modyfing a class with the following approach:
public class FooBar
{
public event EventHandler FooBarEvent;
public void RaiseFooBarEvent(object sender, EventArgs eventArguments)
{
FooBarEvent.Invoke(sender, eventArguments);
}
}
Why accessing public events outside is limited by adding and removing listeners only?
Defining a public event merely gives consumers the ability to subscribe and unsubscribe from it. The ability to raise the event is limited to the type hierarchy which declares the event.
Allowing all subscribers to also be able to raise the event would be a bit chaotic. Imagine for example I had a TextBox class which had a Focused event. If any old consumer could raise the event then the Focused event could easily fire when the TextBox class wasn't actually focused. This would make it nearly impossible to maintain any type of invariant during an event.
Personally I think this is done to properly convey the design principles behind the whole events architecture.
The purpose of an event is to notify a listener of said event occurring in a given object.
What's the point of raising events of classes that don't belong to you?
That's what events are for. If you want to invoke it publicly you probably need delegates not events
Events gives encapsulation,
It prevents other classes from assigning anything to it
It prevents passing it as a parameter to methods
It prevents assigning it to any variable
It prevents calling it from another classes (not even derived classes have access to it)
etc
public accessibility tells that it can be subscribed from anywhere, not invoked from anywhere.
the answer to your question is
An event in C# is a way for a class to provide notifications to clients of that class when some interesting thing happens to an object.
Invoking the event from outside doesn't makes sense therefore it is not allowed.
I think you should change your perspective on how events work. Other classes shouldn't "own" the event and trigger it. Classes which "listen" to the event by "subscribing" to it and do a certain action when this event occurs.
That's the way the language is defined - an event can only be fired by the owning class. If you must fire it from a different class, have the owning class define a public method that will fire the event:
public FireFooBarEvent (object sender, EventArgs args)
{
if(FooBarEvent != null)
FooBarEvent(sender, args);
}
And call this method from any class.
i've two classes.
One class (say A) takes a textbox in c'tor. and registers TextChanged event with private event-handler method.
2nd class (say B) creates the object of class A by providing a textbox.
how to invoke the private event handler of class A from class B?
it also registers the MouseClick event.
is there any way to invoke private eventhandlers?
Short answer: don't.
Declare your event handler as public or, better yet, create a public proxy method, like
public class MyClass
{
private myHandler....
public returnType DoClick() { return myHandler(...); }
}
Giving direct access to a private member defeats the purpose of declaring it private.
Create a public method that both the event handler and the other class can call. In general, it's a bad idea to call event handlers directly. Think carefully about what you're trying to do and you should be able to find a code structure that more closely matches the concept of what you're trying to do. You don't want your other class to click a button; you want your other class to do something that clicking a button will also do.
there is no restriction on both subscribing with private method and firing event with private subscriber. Did you have any errors so far?