I have the following code ...
My Command handler:
public class MyHandler : IHandler
{
// I Want to get rid of this method
public override void ExecuteOperation(BaseOperation operation)
{
// This is a work-around
this.ExecuteOperation(operation as SpecificOperation);
}
public override void ExecuteOperation(SpecificOperation operation)
{
// Do actual work here
}
}
My Command handler dispatcher:
private dynamic FindOperationHandler(TBaseProvisioningOperation operation)
{
... some logic here
return Activator.CreateInstance(handlerType, ... args here ...)
}
My consumer code
public void PerformProvisioningOperation(BaseOperation operation)
{
// Find the correct handler for this operation
var operationHandler = this.FindOperationHandler(operation as TBaseProvisioningOperation);
// make it execute the operation
// NOTE: 'operation' is SpecificOperation type, for example
operationHandler.ExecuteOperation(operation); // <--- problem is here
}
The issue is that when I create an instance of my handler class with the Activator.CreateInstance and pass it a boxed object (i.e. as "BaseOperation") parameter, .NET looks for a method in the handler, which has a parameter of the base type, instead of automatically invoking the one which can handle the object if it were unboxed (i.e. explicitly cast).
Of course we have SpecificOperation : BaseOperation
In other words: I want when I execute operationHandler.ExecuteOperation(operation);, .NET to invoke ExecuteOperation(SpecificOperation operation) instead of ExecuteOperation(BaseOperation operation), because the operation parameter is boxed (i.e. it IS SpecificOperation but is downcast-ed as BaseOperation).
How do I achieve that?
Edit:
public interface IHandler<TOperation> where TOperation : BaseOperation
{
/// <summary>
/// TODO: Get rid of this method
/// </summary>
/// <param name="operation">The operation to execute - boxed</param>
void ExecuteOperation(BaseOperation operation);
/// <summary>
/// Executes the operation
/// </summary>
/// <param name="operation">The operation to execute - unboxed</param>
void ExecuteOperation(TOperation operation);
}
Assuming you're using dynamic here to achieve Double-Dispatch, the problem is that you're casting the wrong object.
It's the operation variable that needs to be casted (in order to defer overload resolution until runtime), not the operationHandler.
Try this instead:
operationHandler.ExecuteOperation(operation as dynamic);
And you can avoid the redundant dynamic definition on your FindOperationHandler:
private IHandler FindOperationHandler(TBaseProvisioningOperation operation)
{
return Activator.CreateInstance(handlerType, ... args here ...) as IHandler;
}
See Double-Dispatch
You should avoid returning dynamic if the complete code is in C#. The Activator.CreateInstance is returning an Object not a dynamic.
Dynamics are for interop between scriptlanguages when the properties/methods aren't strongtyped.
Too bad you didn't described the IHandler interface, but...
I think; The problem you facing is your interface defines that your class must implement the void ExecuteOperation(BaseOperation operation); This way your FindOperationHandler should return an IHandler.
private IHandler FindOperationHandler(TBaseProvisioningOperation operation)
{
... some logic here
return (IHandler)Activator.CreateInstance(handlerType, ... args here ...)
}
And for your handler:
public class MyHandler : IHandler
{
public override void ExecuteOperation(BaseOperation operation)
{
var operation = (SpecificOperation)operation;
// Do actual work here
}
}
Related
I'm reading CLR via C# by Jeffrey Richter which says:
public event EventHandler<NewMailEventArgs> NewMail;
When the C# compiler compiles the line above, it translates this single line of source code into the
following three constructs:
private EventHandler<NewMailEventArgs> NewMail = null;
// 2. A PUBLIC add_Xxx method (where Xxx is the Event name)
public void add_NewMail(EventHandler<NewMailEventArgs> value) {
... // use Delegate.Combine internally
}
// 3. A PUBLIC remove_Xxx method (where Xxx is the Event name) allows methods to unregister interest in the event.
public void remove_NewMail(EventHandler<NewMailEventArgs> value) {
... // use Delegate.Remove internally
}
and the author says:
The System.Windows.Forms.Control type defines about 70 events. If the Control type implemented the events by allowing the compiler to implicitly generate the add and remove accessor methods and delegate fields, every Control object would have 70 delegate fields in it just for the events! Because most programmers care about just a few events, an enormous amount of memory would be wasted for each object created from a Control-derived type. To efficiently store event delegates, each object that exposes events will maintain a collection (usually a dictionary) with some sort of event identifier as the key and a delegate list as the value.
So for example, we should explicitly implementing an event in a type as:
public sealed class EventKey { }
public sealed class EventSet {
private readonly Dictionary<EventKey, Delegate> m_events = new Dictionary<EventKey, Delegate>();
// Adds an EventKey -> Delegate mapping if it doesn't exist or combines a delegate to an existing EventKey
public void Add(EventKey eventKey, Delegate handler) {
...
}
// Removes a delegate from an EventKey (if it exists) and
// removes the EventKey -> Delegate mapping if the last delegate is removed
public void Remove(EventKey eventKey, Delegate handler) {
...
}
// Raises the event for the indicated EventKey
public void Raise(EventKey eventKey, Object sender, EventArgs e) {
... // use Delegate.DynamicInvoke internally
}
}
public class TypeWithLotsOfEvents {
private readonly EventSet m_eventSet = new EventSet();
protected static readonly EventKey s_fooEventKey = new EventKey();
public event EventHandler<FooEventArgs> Foo {
add { m_eventSet.Add(s_fooEventKey, value); }
remove { m_eventSet.Remove(s_fooEventKey, value); }
}
...
}
I don't why this approach is more efficient, it still need to declare each event it contains, and for derived types of TypeWithLotsOfEvents, the child instances will contain all the parent's delegate fields, so nothing you can save? Taking the windows form control type which contains 70 events, any derived control type will have to contain 70 events as well because the inheritance hierarchy
The important thing to note here is that this...
public event EventHandler<FooEventArgs> Foo {
add { m_eventSet.Add(s_fooEventKey, value); }
remove { m_eventSet.Remove(s_fooEventKey, value); }
}
does not generate any fields.
This generates only two methods:
private void add_Foo(EventHandler<FooEventArgs> value) {
m_eventSet.Add(s_fooEventKey, value);
}
private void remove_Foo(EventHandler<FooEventArgs> value) {
m_eventSet.Remove(s_fooEventKey, value);
}
This is rather similar to how auto-implemented properties generate a backing-field plus a getter and setter method, whereas non-auto-implemented properties generate only the getter and setter methods.
Note that you would still have the field s_fooEventKey, but that one is static, so there is only one instance of it ever, rather than one instance of the field per instance of TypeWithLotsOfEvents. So we are all fine.
Try using reflection to print out the private fields of Control. You will see that it doesn't fields that correspond to its events. On the other hand, if you write your own class without using the "dictionary of events" approach, and try to print out its fields, you will see there is a field for each event you declare.
How can I call a RelayCommand by passing in the CanExecute Parameter. The object is being bound as a command paramenter from the view. I have the following piece of code which says 'Delegate Func does not take 0 arguments'. Please help. The definition for OnPrintAllChartsInCurrentView and IsPrintAndExportEnabled is as follows.
RelayCommand m_PrintAllChartsCommand;
public ICommand PrintAllChartsCommand
{
get
{
return m_PrintAllChartsCommand ?? (m_PrintAllChartsCommand = new RelayCommand<object>(
OnPrintAllChartsInCurrentView,
() => IsPrintAndExportEnabled() //This line there is a compiler error
));
}
}
private void OnPrintAllChartsInCurrentView(object obj)
{
//do something. The obj is bound as command parameter from the view.
}
private bool IsPrintAndExportEnabled()
{
//I will do some operation here and change to return true or false later
return false;
}
Here is the RelayCommand class that I am trying to call
namespace GalaSoft.MvvmLight.Command
{
public class RelayCommand<T> : ICommand
{
//
// Summary:
// Initializes a new instance of the RelayCommand class that can always execute.
//
// Parameters:
// execute:
// The execution logic.
//
// Exceptions:
// T:System.ArgumentNullException:
// If the execute argument is null.
public RelayCommand(Action<T> execute);
//
// Summary:
// Initializes a new instance of the RelayCommand class.
//
// Parameters:
// execute:
// The execution logic.
//
// canExecute:
// The execution status logic.
//
// Exceptions:
// T:System.ArgumentNullException:
// If the execute argument is null.
public RelayCommand(Action<T> execute, Func<T, bool> canExecute);
//
// Summary:
// Occurs when changes occur that affect whether the command should execute.
public event EventHandler CanExecuteChanged;
//
// Summary:
// Defines the method that determines whether the command can execute in its current
// state.
//
// Parameters:
// parameter:
// Data used by the command. If the command does not require data to be passed,
// this object can be set to a null reference
//
// Returns:
// true if this command can be executed; otherwise, false.
public bool CanExecute(object parameter);
//
// Summary:
// Defines the method to be called when the command is invoked.
//
// Parameters:
// parameter:
// Data used by the command. If the command does not require data to be passed,
// this object can be set to a null reference
public virtual void Execute(object parameter);
//
// Summary:
// Raises the GalaSoft.MvvmLight.Command.RelayCommand`1.CanExecuteChanged event.
public void RaiseCanExecuteChanged();
}
}
If you are taking a command parameter of type T (which you are declaring as object), the RelayCommand CanExecute requires a single argument of type T and returns bool. You are passing in an anonymous function which takes no arguments and returns a bool. You can simply replace
() => IsPrintAndExportEnabled();
with
arg => { return IsPrintAndExportEnabled(); }
if you do not intend to do anything with the object passed to the CanExecute.
If you do not need a command parameter, then you do not need to declare your RelayCommand as
RealyCommand<object>(execute, canExecute);
it can simply be
RelayCommand(execute, canExecute);
where in this case the Execute would take no arguments and return void and the CanExecute would take no arguments and return a bool.
It should be like this. Notice that RelayCommand canExecute parameter is Func<T,bool> it means that you pass method with the same signature (like below). For more information about Func<T,TResult> see this.
RelayCommand m_PrintAllChartsCommand;
public ICommand PrintAllChartsCommand
{
get
{
return m_PrintAllChartsCommand ?? (m_PrintAllChartsCommand = new RelayCommand<object>(
OnPrintAllChartsInCurrentView,
IsPrintAndExportEnabled
));
}
}
private void OnPrintAllChartsInCurrentView(object arg)
{
}
private bool IsPrintAndExportEnabled(object arg)
{
return false;
}
This is what works for me (IsRealShunter is a boolean property):
RaiseAlarmClickCommand = new RelayCommand<Guid>(RaiseAlarmClick, x => IsRealShunter);
RaiseAlarmClick is a method:
private void RaiseAlarmClick(Guid idPrinter) {...}
One small note, if something gets updated in your view model and you want to make sure your RelayCommand reflects the changes, call this from where the change occured:
RaiseAlarmClickCommand.RaiseCanExecuteChanged();
This is what worked for me. In case if it helps anyone. First look at the RelayCommand, the way I am declaring is wrong. It should be RelayCommand<object> This is the complete declaration and usage.
RelayCommand<object> m_PrintAllChartsCommand;
public ICommand PrintAllChartsCommand
{
get
{
return m_PrintAllChartsCommand ?? (m_PrintAllChartsCommand = new RelayCommand<object>(
OnPrintAllChartsInCurrentView, IsPrintAndExportEnabled));
}
}
private void OnPrintAllChartsInCurrentView(object arg)
{
}
private bool IsPrintAndExportEnabled(object arg)
{
}
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 made a TV-Player in c# using directshowlib-2005.
now I made a method to search for available channels.
I want this method to run in a different thread so my GUI won't freeze, but I get an error when I try to set the channel in the method. It can't find the IAMTVTuner interface in my graph, altough I know it's there.
If I don't use a different thread, the method works just fine (but my GUI freezes for a while)
I know it has to do something with apartments, but is there a way I can acces that interface in a different thread then the thread where created my graph in?
This problem is because some com classes or interfaces like in the DirectShowLib should be just accessed from the same thread that it was created on.
So the solution to this problem is to implement ISynchronizeInvoke "System.ComponentModel.ISynchronizeInvoke".
For example if you need to access methods in the class named Media that uses internally some classes or methods from the DirectshowLib in multithreading mode, you have to check if invoke required by using InvokeRequired and if true you have to access it via Invoke method.
To demonstrate how to implement ISynchronizeInvoke interface here is a snippet from a code that I develop some time ago in C# 2.0
public abstract class Media : ISynchronizeInvoke
{
//....
private readonly System.Threading.SynchronizationContext _currentContext = System.Threading.SynchronizationContext.Current;
private readonly System.Threading.Thread _mainThread = System.Threading.Thread.CurrentThread;
private readonly object _invokeLocker = new object();
//....
#region ISynchronizeInvoke Members
public bool InvokeRequired
{
get
{
return System.Threading.Thread.CurrentThread.ManagedThreadId != this._mainThread.ManagedThreadId;
}
}
/// <summary>
/// This method is not supported!
/// </summary>
/// <param name="method"></param>
/// <param name="args"></param>
/// <returns></returns>
[Obsolete("This method is not supported!", true)]
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
throw new NotSupportedException("The method or operation is not implemented.");
}
/// <summary>
/// This method is not supported!
/// </summary>
/// <param name="method"></param>
/// <param name="args"></param>
/// <returns></returns>
[Obsolete("This method is not supported!", true)]
public object EndInvoke(IAsyncResult result)
{
throw new NotSupportedException("The method or operation is not implemented.");
}
public object Invoke(Delegate method, object[] args)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
lock (_invokeLocker)
{
object objectToGet = null;
SendOrPostCallback invoker = new SendOrPostCallback(
delegate(object data)
{
objectToGet = method.DynamicInvoke(args);
});
_currentContext.Send(new SendOrPostCallback(invoker), method.Target);
return objectToGet;
}
}
public object Invoke(Delegate method)
{
return Invoke(method, null);
}
#endregion//ISynchronizeInvoke Members
}
Is this an appropriate way of handling cross-thread operations?
Should I use a new property name, something like "EditValueThreadSafe" instead of overriding "EditValue"? I don't think there is an issue with the changes to the implementation of EditValue, as the base property is called regardless.
namespace MyApplication.Components
{
using System.Windows.Forms;
/// <summary>
/// Thread-safe implementation of the DevExpress.XtraEditors.ComboBoxEdit class.
/// </summary>
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
/// <summary>
/// Gets or sets the edit value.
/// </summary>
/// <value>The edit value.</value>
public override object EditValue
{
get
{
return base.EditValue;
}
set
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(delegate
{
this.SetEditValue(value);
}));
}
else
{
this.SetEditValue(value);
}
}
}
/// <summary>
/// Sets the edit value.
/// </summary>
/// <param name="value">The value.</param>
private void SetEditValue(object value)
{
base.EditValue = value;
}
}
}
You can also delegate to another method that does the work, and in that method, if on the wrong thread, (BeginInvoke returns true), then call the same method back again. Doing that that eliminates the need to duplicate code.
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
public override object EditValue
{
get
{
return base.EditValue;
}
set
{
SetValue(value);
}
}
private void delegate SetValueDlg(object valeu);
private void SetValue(object value)
{
if (this.InvokeRequired)
this.BeginInvoke(
(SetValueDlg)SetValue, // calls itself, but on correct thread
new object[] { value });
else
base.editValue = value;
}
}
You can also use the Action() generic class to eliminate need to create explicit delegate class...
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
public override object EditValue
{
get { return base.EditValue; }
set { SetValue(value); }
}
private void SetValue(object value)
{
if (this.InvokeRequired)
this.BeginInvoke(
new Action<object>(SetValue), // calls itself, but on correct thread
new object[] { value });
else
base.editValue = value;
}
}
It's thread-safe, yes, though be wary of overriding a property and fundamentally changing the behaviour. Changing the implentation is fine, but this property now behaves very differently, removing the possibility of a specific exception but introducing a possible deadlock or blocking condition, which impacts on the calling code.
So yes, this is the correct use of InvokeRequired & Invoke, but I'd recommend creating a separate, purpose-specific and thread-safe property that is advertised as such.
My UI methods like yours end up looking like this:
public void setStatusLabelText(String s)
{
if (footerStatusLabel.InvokeRequired) {
StringUpdateInvokeDelegate callback = new StringUpdateInvokeDelegate(setStatusLabelText);
this.Invoke(callback, new object[] { s });
}
else {
this.footerStatusLabel.Text = s;
}
}
(this may be old for .net these days - but the point is that you can just do the operation inside this method if you are already on the right thread - makes it a little less irritating to read, but still annoying compared to Java, IMO).
I'll inject my 2 cents here. The actual calls to InvokeRequired/BeginInvoke/Invoke are not entirely thread safe. (see Avoiding the woes of Invoke/BeginInvoke in cross-thread WinForm event handling?) I would recommend finding some way of isolating the calls to these in a single place, utility api, extension method, or the like. In the article above there is complete code for a class that wraps a delegate to provide thread-safe behavior.