Search code examples
c#delegatesout-parameters

c# generic delegate with out parameter - define and call


I'm currently refactoring an existing DAL which has a facade the user calls and an inner class that does the actual work dependent upon the ADO.Net provider to use e.g. SqlProvider, and I'm trying to ensure that code is DRY, I've done ok by using a Func so I can do:

return RunCommand(c => c.ExecuteNonQuery(commandText, parameters));

And the RunCommand method looks like:

    private T RunCommand<T>(Func<Commands, T> toRun)
    {
        return toRun(CreateCommand());
    }

The CreateCommand() method simply builds the command object to use, this then allows me to have a single method that handles all the calls that just return the expected type e.g. DataSet, DataReader, etc

The problem I have is that several calls on the facade provide an out parameter I know should be able remove the repeated code if I can use a delegate but after a lot of googling & experimenting I've not managed to work out how. The code is:

 Commands commands = CreateCommand();
 return commands.ExecuteNonQuery(out cmd, commandText, parameters);

What I'd really like to do is be able to call:

return RunCommand(c => c.ExecuteNonQuery(out cmd, commandText, parameters));

I've seen this existing question but for the life of me I cannot work out how to turn that into what I need.

This delegate would seem to be what I need private delegate V TestOutParameter<T, U, V>(T a, out U b, V c); but the code I've got for calling it just isn't right:

    private V RunCommand<T, U, V>(TestOutParameter<Commands, DbCommand, V> commandToExecute)
    {
        DbCommand cmd;
        return (V)commandToExecute(CreateCommand(), out cmd);
    }

Can anybody help me as this has been driving me mad for a week!


Solution

  • Your delegate has three parameters instead of two. Assuming you want it to mirror Func, instead of:

    private delegate V TestOutParameter<T, U, V>(T a, out U b, V c);
    

    you should have:

    private delegate V TestOutParameter<T, U, V>(T a, out U b);
    

    I would personally recommend you rename it to something like:

    private delegate TResult FuncOut<T1, T2, TResult>(T1 arg1, out T2 arg2)