3

I want to pass a method as an argument to remove repetitive code from my program. This is the functionality I would like:

 private void sqlQuery(Method sqlMethod)
{
    conn.ConnectionString = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
    try
    {
        //open SQL connection
        conn.Open();
        sqlMethod();
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.Write(ex.ToString());
    }
    finally
    {
        conn.Close();
    }
}

Using:

private void insertTemplate()
{
    //create SQL command
    SqlCommand insertTemplate = new SqlCommand("INSERT INTO [SavedDescriptionTemplates] (SavedDescription, UserId, CreatedDate) VALUES (@descriptionParam, @userIdParam, @createdDateParam)", conn);
    //create and assign parameters
    insertTemplate.Parameters.AddWithValue("@descriptionParam", descriptionInput.Text);
    insertTemplate.Parameters.AddWithValue("@userIdParam", Int32.Parse(userNameDropDown.SelectedItem.Value));
    insertTemplate.Parameters.AddWithValue("@createdDateParam", DateTime.Now);
    //execute command and retrieve primary key from the above insert and assign to variable
    insertTemplate.ExecuteNonQuery();
}

The call would be:

sqlQuery(insertTemplate());

Is this possible?

David Tunnell
  • 7,252
  • 20
  • 66
  • 124
  • In addition to the duplicate questions, we also have [Action](http://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx) available – musefan Jul 03 '13 at 14:04
  • 1
    Please consider wrapping your database code in a using block like using (SqlConnection connection = new SqlConnection(connectionString)){...} – DOK Jul 03 '13 at 14:09
  • 1
    Note you would be much better off defining your connection object as a local variable to `sqlQuery` and passing it as a parameter to your delegate, rather than making it an instance field and having other methods reference a connection that they don't know whether or not is open. Then you'll want to use the `Action` delegate, not `Action`, and have `insertTemplate` accept the connection as a parameter. This ensures that everywhere the connection can be accessed you *know* it's open. Also can be combined with DOK's comment. – Servy Jul 03 '13 at 14:11

7 Answers7

4

Use the Action delegate.

Change

private void sqlQuery(Method sqlMethod)

into

private void sqlQuery(Action sqlMethod)

and

sqlQuery(insertTemplate());

into

sqlQuery(insertTemplate);
Ahmed KRAIEM
  • 10,267
  • 4
  • 30
  • 33
1

Yes, but slightly different...

Try this:

sqlQuery(insertTemplate); // don't CALL the method, just name it

And declare sqlQuery like this:

private void sqlQuery(Action sqlMethod)
Daren Thomas
  • 67,947
  • 40
  • 154
  • 200
1

You can achieve that with a delegate.

Use for example Action:

private void sqlQuery(Action action)
{
    conn.ConnectionString = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
    try
    {
        //open SQL connection
        conn.Open();

        action();
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.Write(ex.ToString());
    }
    finally
    {
        conn.Close();
    }
}
Bidou
  • 7,378
  • 9
  • 47
  • 70
1

Look into delegates. In your case, since your method takes no parameters, you can use the built in Action delegate:

private void sqlQuery(Action sqlMethod)
{
    //...
}

sqlQuery(insertTemplate);
Matt Burland
  • 44,552
  • 18
  • 99
  • 171
1

Blocks of logic in C# are passed as delegates. There are several ways of declaring a delegate - you can define a custom one, or use one of predefined types:

  • You can use Action<...> for delegates that do not return values, or
  • You can use Func<...,R> for delegates that return values.

Here is one way to define a function that takes a delegate:

private void sqlQuery(Action<IDbConnection> sqlMethod) {
   ...
   sqlMethod(conn);
   ...
}

Call sqlQuery with a named or an anonymous delegate which could be defined inline, as a named method, or as a lambda expression:

// Using some method that takes IDbConnection
sqlQuery(MySqlMethod);
// Using an anonymous delegate
sqlQuery((conn) => {
    ... // Do something with conn
});
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

Yes. You need to use delegates, anonymous functions, or lambda expressions.

Here's a simple example:

public void SomeMethod(Action<string> passedMethod)
{
    passedMethod("some string");
}

public void Caller()
{
    SomeMethod(x => Console.WriteLine(x));
}

If you run "Caller", it would output "some string".

John Fisher
  • 22,355
  • 2
  • 39
  • 64
0

Delegates are the answer -> Microsoft on C# Delegates

public void delegate MyDelegate();

MyDelegate del = this.insertTemplate;

private void sqlQuery(MyDelegate sqlMethod)
{
 ...
 del();
 ...
}
dkoch74
  • 115
  • 9