Home > Software engineering >  Why is this lambda expression valid for the constructor argument
Why is this lambda expression valid for the constructor argument

Time:09-19

I have a constructor of RelayCommand set as:

public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)

And in another script I have:

    private Server _server;
    public RelayCommand ConnectToServerCommand {get; set;}

    public MainViewModel() // constructor
    {
        _server = new Server();


        //this syntax is confusing to me - not sure what it's doing
        ConnectToServerCommand = new(o => _server.Connect());
    }

I don't really understand the syntax for the ConnectToServerCommand in the MainViewModel constructor.

The RelayCommand takes in an Action with an object parameter type, yet the _server.Connect() method has this signature:

// Server
public void Connect()

Why does it allow this method to be used when it does not have an object as one of it's arguments? Given the action is set to Action<object>. How is it considering this a valid method signature?

I am still new to this - so I think the lambda expression is confusing me a little but, not sure how they connect together here.

CodePudding user response:

Your lambda defines a function/method hat accepts an object o, and just ignores it. That’s fine, the signature says you have to accept one, not that it has to be useful.

public int Something(object o)
{
    return 12;
}

is a fine, though inefficient (because it takes an unnecessary parameter) function.

CodePudding user response:

This Method

o => _server.Connect()

is the same as this Method

void Anon(object o) 
{
    // argument o is ignored
    _server.Connect();
}

making this code equivalent to yours:

private Server _server;
public RelayCommand ConnectToServerCommand {get; set;}

// un-lambda-ed
void Anon(object o) 
{
    _server.Connect();
}

public MainViewModel() // constructor
{
    _server = new Server();

    // no confusion
    ConnectToServerCommand = new(Anon);
}

Let's have both calls in the constructor:

public MainViewModel() // constructor
{
    _server = new Server();

    ConnectToServerCommand = new(o => _server.Connect());
    // no confusion
    ConnectToServerCommand = new(Anon);
}

and then compare the generated Intermediate Language:


MainViewModel:
IL_0000:  ldarg.0     
IL_0001:  newobj      UserQuery Server..ctor
IL_0006:  stfld       UserQuery._server              // _server = new Server();
IL_000B:  ldarg.0     
IL_000C:  ldarg.0     
IL_000D:  ldftn       UserQuery.<MainViewModel>b__0  // our lamda function, see below
IL_0013:  newobj      System.Action<System.Object>..ctor
IL_0018:  newobj      UserQuery RelayCommand..ctor
IL_001D:  call        UserQuery.set_ConnectToServerCommand
IL_0022:  ldarg.0     
IL_0023:  ldarg.0     
IL_0024:  ldftn       UserQuery.Anon                 // our Anon call
IL_002A:  newobj      System.Action<System.Object>..ctor
IL_002F:  newobj      UserQuery RelayCommand..ctor
IL_0034:  call        UserQuery.set_ConnectToServerCommand
IL_0039:  ret         

<MainViewModel>b__0:  // generated by the compiler for us, the lambda
IL_0000:  ldarg.0     // object o, nothing gets done with that
IL_0001:  ldfld       UserQuery._server
IL_0006:  callvirt    UserQuery Server.Connect
IL_000B:  ret         

Anon:
IL_0000:  ldarg.0     // object o, nothing gets done with that
IL_0001:  ldfld       UserQuery._server
IL_0006:  callvirt    UserQuery Server.Connect
IL_000B:  ret         

That is remarkable similar.

  • Related