tags:

views:

496

answers:

4

I'm working through Josh Smith's CommandSink Example and the base.Executed += (s, e) =>... structures are throwing me, can someone help make this crystal clear?

what I understand:

  • base.CanExecute is the event on the inherited class CommandBinding
  • the += is adding a delegate to that event
  • the delegate is the anonymous function which follows that line

what I don't understand:

  • is (s,e) is the signature of that function?
  • where is the variable s used?

Here is the code in context:

public class CommandSinkBinding : CommandBinding
    {
        #region CommandSink [instance property]

        ICommandSink _commandSink;

        public ICommandSink CommandSink
        {
            get { return _commandSink; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("Cannot set CommandSink to null.");

                if (_commandSink != null)
                    throw new InvalidOperationException("Cannot set CommandSink more than once.");

                _commandSink = value;

                base.CanExecute += (s, e) =>
                    {
                        bool handled;
                        e.CanExecute = _commandSink.CanExecuteCommand(e.Command, e.Parameter, out handled);
                        e.Handled = handled;
                    };

                base.Executed += (s, e) =>
                    {
                        bool handled;
                        _commandSink.ExecuteCommand(e.Command, e.Parameter, out handled);
                        e.Handled = handled;
                    };
            }
        } 
        ...
+7  A: 

(s, e) is the Method Parameter Signature for the event handler (in this case the anoymous method that's defined)

think (object Sender, EventArgs e)

The s parameter just isn't being used in the rest of the method which is fine. It has to be there to match the expected signature

base.CanExecute += (s, e) =>
                    {
                        bool handled;
                        e.CanExecute = _commandSink.CanExecuteCommand(e.Command, e.Parameter, out handled);
                        e.Handled = handled;
                    };

is the equivalent of doing

base.CanExecute += new EventHandler(myMethod_CanExecute);

///....
protected void myMethod_CanExecute(object sender, EventArgs e)
{
    bool handled;
    e.CanExecute = _commandSink.CanExecuteCommand(e.Command, e.Parameter, out handled);
    e.Handled = handled;
};
Eoin Campbell
so you could also write (sender, e) or even (whatevernnn, e), it is just a placeholder, right?
Edward Tanguay
Correct. The (s,e) or (jimbob, blahvar) signature is just your naming convention for the parameters so that you can reference them in the rest of the anonymous method declaration. But you should stick to something reasonably obvious like (s,e) / (sender, e) / (sender, args)
Eoin Campbell
+1  A: 

Yes, (s, e) is the signature. The function must have the signature defined by the event (CommandBinding.CanExecute: http://msdn.microsoft.com/en-us/library/system.windows.input.commandbinding.canexecute.aspx).

The variable s is not used, in this particular example. The event follows the same design pattern as most other events in .NET. The first parameter will usually contain a reference to the instance that raised the event, the second parameter contains an EventArgs class (or a more specialized class that inherits EventArgs). In this case, the second parameter would be a instance of the type CanExecuteRoutedEventArgs (unless I misinterpreted any information).

Fredrik Mörk
+1  A: 

(s, e) is sort of the signature -- but its interpretation depends on inference from the C# compiler. The C# compiler knows that the type of Executed is ExecutedRoutedEventHandler, which is equivalent to void delegate(object, ExecutedRoutedEventArgs). It sees the lambda expression (s, e) => { ... } and figures out that s must be of type object, e must be of type ExecutedRoutedEventArgs, and the whole expression is a function from (object, ExecutedRoutedEventArgs) to void.

As others have noted, s is there because if it weren't there, the anonymous function wouldn't conform to the signature required by ExecutedRoutedEventHandler. Some languages have a special notation to say "this parameter has to be here for formal technical reasons, but I'm not interested in it." C# doesn't, so it has to name the parameter even though it's not used.

itowlson
ok, in System.Windows.Input ExecutedRoutedEventHandler is defined thusly: public delegate void ExecutedRoutedEventHandler(object sender, ExecutedRoutedEventArgs e) which determines signature, makes sense
Edward Tanguay
A: 
base.CanExecute += (s, e) =>
                {
                    bool handled;
                    e.CanExecute = _commandSink.CanExecuteCommand(e.Command, e.Parameter, out handled);
                    e.Handled = handled;
                };

What you are seeing here is Lambda in C# 3.

In C# 2 this would be:-

    base.CanExecute += delegate(object s, EventArgs e)
                {
                    bool handled;
                    e.CanExecute = _commandSink.CanExecuteCommand(e.Command, e.Parameter, out handled);
                    e.Handled = handled;
                };

C# 3 allows this (s, e) contraction since its able to imply the types from the right hand side (it can see that CanExecute takes a delegate type and what types its parameters are).

The => expresses the function to execute, often braces are not needed for a simple single line expression.

AnthonyWJones
thanks, I recall reading that a feature of C# 3 is that it can "infer information" and didn't really understand it, this must be an example of that: it can infer delegate parameter types and the fact that there is a delegate there in the first place
Edward Tanguay