Add events using Extension methods - c#

I have found several posts about Raising events with an extension method, however my question is a bit different:
I have an interface like this:
public interface IStateMachine
{
void SetState(IState NewState);
IState GetState();
}
Using this interface I can create an extension method like follows:
public static void ChangeState(this IStateMachine StateMachine, IState NewState)
{
StateMachine.GetState().Exit();
StateMachine.SetState(NewState);
StateMachine.GetState().Enter();
}
What I really want is that there will be events that need to be fired, e.g.: a statechange-event.
However I don't want the StatechangeEvent to be a part of the IStateMachine interface, but it seems that that's the only way. I have several classes that implement IStateMachine, and therefore I have to redo the same code every time.

In C#, there are only extension methods. No extension properties or events.
You will have to declare the event on the interface.
To avoid the need to write the same event code over and over, you can create a base class.
Another possibility would be to "manually" implement the Publish-Subscribe pattern. That's what events in C# are.
You can add the extension methods Subscribe and Unsubscribe to IStateMachine.
They would use a possibly static class StateMachineSubscribers which also exposes the Subscribe and Unsubscribe methods. Additionally, it exposes a Raise method used by your ChangeState extension method.

The event with its corresponding delegate can be a part of a concrete class that implements that IStateMachine interface. So if you call SetState, on interface, its concrete implementaion of some concrete class is called, which inside of it raises an event you want.

Related

C# Subscribing to Events Using Interfaces

I have recently started working with C# events and I am really liking the ease of use they offer (I come from a java background where we have to do all this event stuff manually).
However, there is one thing from my java background that I am missing: the inheritance side.
In java, if you want to subscribe to an event, you would inherit an interface such as IKeyListener. The interface would contain all of the method event signatures which you would then implement in the subscribing class. Whenever a key would be pressed, these implemented methods would be fired. Much the same as C#. However, unlike in java, I am unable to identify which classes subscribe to certain events because they don't actually inherit anything.
So if I wanted a list of objects which have key press event support I could do
List<IKeyListener> keyListeners = new ArrayList<IKeyListener>();
However, I don't see any good way to do this in C#. How would I be able to create list similar to the one above? Preferably without much "hackiness".
Thank you.
In C# you can define the event in an interface like this:
public interface IDrawingObject
{
event EventHandler ShapeChanged;
}
Then you can do what you want and store them like this:
var shapes = new List<IDrawingObject>();
A class can then implement the interface like this:
public class Shape : IDrawingObject
{
public event EventHandler ShapeChanged;
void ChangeShape()
{
// Do something here before the event…
OnShapeChanged(new MyEventArgs(/*arguments*/));
// or do something here after the event.
}
protected virtual void OnShapeChanged(MyEventArgs e)
{
if(ShapeChanged != null)
{
ShapeChanged(this, e);
}
}
}
So in other words the event becomes part of the interface and if a class implements that interface, the class must provide an implementation for the event as well. That way you are safe to assume the implementing class has the event.
Finally every event will need to share some info about the event. That class can inherit the EventArgs class like below:
public class MyEventArgs : EventArgs
{
// class members
}

Call method from abstract class when abstract method called in the derived class

I'm making a user interface in XNA with a custom control setup. I have a base abstract class called Clickable, this contains methods that are run when various actions happen, I.e; OnClick, OnRelease.
I have tried to implement listeners into this, i use the below two methods to get this to work:
public void RegisterClickListener(Action<Vector2> ClickMethod)
{
listners.Add(ClickMethod);
}
public void OnClickMethod(Vector2 pos)
{
foreach (Action<Vector2> func in listners)
func(pos);
}
RegisterClickListener adds the method passed in the parameters to a list of methods to be called when the OnClickMethod method fires. OnClickMethod simply iterates through the list and calls each method.
I need a way to be able to call OnClickMethod each time my abstract method OnClick (bellow) is called. Currently i have to to manually invoke OnClickMethod each time i use OnClick, which is not ideal.
public abstract void OnClick(Vector2 pos);
Is there a way i can do this while keeping OnClick abstract? Or will i have to take off the abstract and call base each time i use it?
You're looking for Template method pattern. Create a method which acts as a template(does some steps in fixed order), then give the client options to override only small portion of it.
public void OnClick(Vector2 pos)
{
OnClickCore(pos);
OnClickMethod(pos);
}
public abstract void OnClickCore(Vector2 pos);
Now OnClick is a template method which defines set of rules that need to be invoked when it is called.

PostSharp aspect to introduce an Interface AND LocationInterception pointcuts

I have a need to implement a complex aspect which needs to be able to introduce an interface, as well as several pointcuts. I'm not sure how to do this.
My goal is to intercept some field setters on a class, so that I can introduce some behaviour (via event handlers on the decorated fields). I want to transform some data, and then raise an event which is declared on a specific interface, so I want to introduce this interface to the class which contains these fields.
The simplest concept would be a container which captures all events on its children and transforms them into a single external event on the container class.
So, I know how to introduce method pointcuts using LocationInterceptionAspect;
public override void OnSetValue(LocationInterceptionArgs args)
{
// attach event handler to args.Value.SomeEvent,
}
And also how to introduce interfaces/methods with an InstanceLevelAspect.
But not how to combine the 2 into a single aspect.
I can't simply introduce an interface or member inside a LocationInterceptionAspect, as the scope is the location, not the containing type, and it won't compile.
I could always separate this into 2 aspects, however this means each aspect will not function independently, and I'd have to ensure both are always applied together.
It appears that I can add an OnLocationSetValueAdvice (via attributes) to an InstanceLevelAspect, and this works.
[IntroduceInterface(typeof(IMyInterface)]
public class CustomAspect : InstanceLevelAspect
{
[OnLocationSetValueAdvice]
[MulticastPointcut(Targets = MulticastTargets.Field, Attributes = MulticastAttributes.Instance)]
public void OnSetValue(LocationInterceptionArgs args)
{
...
}
}

what does event inside the interface mean?

I know the class implementing an interface must implement all its method. But what does event inside the interface mean?
It means that the type must implement the event - so that clients can subscribe to those events.
Think of events as pairs of methods (add/remove) just as properties have get/set. Just as you can have properties in interfaces, you can have events: the implementation has to provide the appropriate add/remove methods and the metadata to tie them to the event. In C# this can be done using field-like events:
public event EventHandler EventFromInterface;
or with explicit add/remove methods:
public event EventHandler EventFromInterface
{
add { ... }
remove { ... }
}
It means anything implementing that interface must raise that event. Pretty much the same as a Method or Property within an interface.

WPF - Why there is no "OnDataContextChanged" overridable method?

The FrameworkElement object has DataContextChanged event. However, there is no OnDataContextChanged method that can be overridden.
Any ideas why?
If a method is virtual, then the user has the option to either augment the base functionalty by calling the base class method or replace the base class functionality by failing to call the base class method. For OnEvent() methods, if you don't call the base class method then the event will not be raised (that's the responsibility of the base class method.) If the base class performs some kind of state management inside of the OnEvent method, this means that the derived class can accidentally invalidate the state of the object if the user chooses to omit a call to the base class method. Documentation can specify "please always call the base class method", but there's no way to enforce it.
When I see an event that doesn't have a virtual OnEvent() method, I usually assume the method performs some kind of internal state management and the designers of the class want to guarantee their state management runs. This isn't the case in FrameworkElement, and it's not the only event that doesn't follow the pattern, so I'm curious what the reasoning is.
I dug around in Reflector to see if I could discover a reason. There is an OnDataContextChanged() method, but it's a dependency property change handler and doesn't follow the standard event pattern. This is probably the reason for not making it protected virtual. It's non-standard, so it would be confusing. It's static, so you wouldn't be able to override it anyway. Since it's called automatically by the dependency property framework and you are unable to override it, I believe we have the reason why it's private instead of static virtual.
You could use a different pattern to expose the normal event pattern:
class FrameworkElement
{
// difference: use DataContextPropertyChanged as the change callback
public static readonly DependencyProperty DataContextProperty = ...
protected virtual void OnDataContextChanged(...)
{
// raise the DataContextChanged event
}
private static void DataContextPropertyChanged(...)
{
((FrameworkElement)d).OnDataContextChanged(...);
}
}
My guess why they didn't do this? Usually you call OnEvent() to raise the event. The event is automatically raised when DataContext changes, and it doesn't make sense for you to raise it at any other time.
Good question.
I'm just guessing, but looking in Reflector I'd say it's just laziness, perhaps with a pinch of (unfounded?) performance concerns. FrameworkElement has a generic EventHandlersStore which is responsible for maintaining event information (delegates) for a whole bunch of events. The add and remove logic in the CLR events (such as DataContextChanged) simple call into the EventHandlersStore with the appropriate key.
There is a generic RaiseDependencyPropertyChanged method that is called to raise all different sorts of events. There is also a private OnDataContextChanged method that calls the RaiseDependencyPropertyChanged method. However, it is static and registered as part of the d-prop metadata.
So, in short, I see no technical reason not to include an overridable OnDataContextChanged method. Just looks like a short-cut in implementation to me.
Is this merely academic, or are you trying to achieve something here?
Silverlight Note:
At of Silverlight Beta 4 there IS no DataContextChanged event (well its not public at least).
The Microsoft Connect bug report has been marked as 'Fixed' but with no indication of what that actually means.
In the meantime you need a workaround such as this one from CodeProject - which is very simple and should be easy to switch out if Microsoft ever actually makes the event public.
Dependency properties usually don't have corresponding virtual methods for raising the event because it's expected that the change events will be managed by the dependecy property system itself.
What you can override however, to handle any dependency property changing is DependencyObject.OnPropertyChanged like so:
class MyClass : FrameworkElement {
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) {
base.OnPropertyChanged(e);
if (e.Property == FrameworkElement.DataContextProperty) {
// do something with e.NewValue/e.OldValue
}
}
}

Categories

Resources