3

Is it possible to get the number of parameters being passed to a method in run time, and if so how?

For instance, if if would be possible, I could have a database interaction method as follows,

public void AddSomethingToDatabase(string parameter1, string parameter2)
{
   ...
   foreach(param in parameters)
   {
      sp.AddParameter(GetName(param),param));
   }
   conn.Execute(...);
}

I am attempting to not have to add/change a line in code each time my stored procedure parameters change, instead only changing the method signature with the correct stored procedure parameters. In this case, parameter1 and parameter2 would be the actual names of the parameters in the stored procedure. Any ideas?

George Johnston
  • 31,652
  • 27
  • 127
  • 172
  • 2
    I would pass the parameters as a collection and loop through that. Is that an option for you ? – Steven Ryssaert May 20 '11 at 13:38
  • 1
    Yeah I agree with Uw Concept a Data Transfer Object is a better solution http://en.wikipedia.org/wiki/Data_transfer_object – Ivo May 20 '11 at 13:40
  • @Uw That would just shift the extra code elsewhere. I would still need to specifically define the name of the stored procedure parameter within a collection, just within the object calling this procedure. I'm trying to make the parameters of the method the definition of the stored procedure. – George Johnston May 20 '11 at 13:41
  • not necessarily. However I do believe in setting the parameters of your stored procedures manually is more robust than making it dependant on the number of parameters in your method. What if you want to add a boolean `isUpdateOrInsert`, or anything? – Steven Ryssaert May 20 '11 at 13:54

7 Answers7

4

Without reflection:

public int AddSomethingToDatabase(params object[] parameters)
artplastika
  • 1,972
  • 2
  • 19
  • 38
3

Can you pass the parameters as a collection? This way it is unlimited and easy to use. This is how I do it for my own projects

public void AddSomethingToDatabase(Dictionary<string, object> parameters)
{
   foreach(KeyValuePair<string, object> param in parameters)
   {
      string paramname = param.Key;
      object paramvalue= param.Value;
      sp.AddParameter(paramname, paramvalue);
   }
   conn.Execute(...);
}

EDIT : I'd like to clarify more how I used this method in my own programs.

I specify the database procedure parameters in the method itself, and pass the parameters like you do. I do realise there is a better way, like using DTO's

public void AddSomethingToDatabase(string param1, int param2)
{
   Dictionary<string, object> parameters = new Dictionary<string, object>();
   parameters.Add("pID", param1);
   parameters.Add("pName", param2);

   ModifyDatabase(parameters, "update_myTable");
}

public void ModifyDatabase(Dictionary<string, object> parameters, string procedure)
{
   // Do necessary checks on parameters here
   // Check database availability
   // And many other checks that would be recurring for every database transaction
   // ... that's why I have them all in one place. Executing Queries is the same
   // ... every time. Why would you write the error handling twice? :-)

   // Loop parameters and fill procedure parameters

   // Execute the lot
}
Steven Ryssaert
  • 1,989
  • 15
  • 25
  • @Uw In order to call this method, I would have to have knowledge outside this method of what the parameters for the stored procedure are. I want to be able to blindly call the `AddSomethingToDatabase` function, using only the signature of the method as the guide. The calling object has no knowledge of the database, just what this method wants. The method itself has no knowledge of what the database wants, except what the signature defines. – George Johnston May 20 '11 at 13:46
  • @George I can see your approach. It seems all very beautiful until you want to pass an extra parameter to your method that will not be used in your procedure. I'm not judging you or your programming principals, just trying to give your problem a view from a different angle, that's all :-) – Steven Ryssaert May 20 '11 at 13:49
  • 1
    @Uw I definately understand what your concerns are, but these methods are only shadowing stored procedures. Think abstract code generation. When you call this method, you call the stored procedure, nothing more. I wouldn't say it could never change, and there won't be instances where the scenerio you mentioned wouldn't come into play -- but those would really be corner cases that I would have to attack differently -- such as overloading the method. Appreciate your input though! :) – George Johnston May 20 '11 at 13:57
  • +1 @George for your vision on Overloading. It's so great to see the numerous approaches in saving data from objects to classes! I've learned from your post :) thanks – Steven Ryssaert May 20 '11 at 14:07
  • @Uw For instance, if I code gen'd objects based off my stored procedure, the method name would be generated, as well as the parameters, and the an isUpdateOrInsert flag would be on the stored procedure itself -- not special rules/parameters on the method. The method is a direct 1 to 1 copy of the stored procedure. – George Johnston May 20 '11 at 14:10
  • @George That last sentance is **the** key phrase for your initial question :) – Steven Ryssaert May 20 '11 at 14:13
1
Console.WriteLine(MethodInfo.GetCurrentMethod().GetParameters()[0].Name);

Will write the name of the first parameter to the current method.

As for getting the value, it seems reflection doesn't have this.

Marino Šimić
  • 7,318
  • 1
  • 31
  • 61
1
public class NameValue
{
    public NameValue(string name, object value)
    {
        Name = name;
        Value = value;
    }
    public string Name { get; set; }
    public object Value { get; set; }
}

private void DoSomething(params NameValue[] args)
{
    foreach (var nameValue in args)
    {
        //sp.AddParameter(nameValue.Name, nameValue.Value);
    }
}

private void GenerateTable(Table table)
{
    DoSomething(new NameValue("name", "Jonas"), new NameValue("Age", 99));
}
yanckst
  • 438
  • 4
  • 17
jgauffin
  • 99,844
  • 45
  • 235
  • 372
1

If 3rd-party component is an option, looks like BLToolkit would do exactly what you expect.

Call definition for the stored procedure in your code will look like in the snippet below and post-processed by BLT to pass all parameters to the sproc (by default it expects same names in sproc and method signature).

[SprocName("sp_MySproc")]
public abstract void CallMySproc(string @parameter1, string @parameter2); 

There are more detailed code examples in unit tests.

As a disclaimer, BLT supports it, but I didn't use it with Mono myself.

Edit: BLT source code is available and might help with the question, but its implementation idea is somewhat different from yours. Instead of using reflection on each call, it does it only when class is used for the first time, implements declared abstract method, and after that point there is no performance downgrade.

DK.
  • 3,173
  • 24
  • 33
1

I don't think you can get the parameter values, even with reflection. If you don't reference them specifically in the method body, the compiler will just optimise them away. See these posts for example: Can I get parameter names/values procedurally from the currently executing function?

Community
  • 1
  • 1
Rob
  • 4,327
  • 6
  • 29
  • 55
0
public class SPParamCollection : List<SPParams>{ }
public struct SPParams
{
    public string Name { get; set; }
    public object   Value { get; set; }
    public SqlDbType SqlDbType { get; set; }
}
public void AddSomethingToDatabase(SPParamCollection arrParam)
{
    foreach (SPParams param in arrParam)
        cmd.Parameters.Add(param.Name, param.Value);
}
Steven Ryssaert
  • 1,989
  • 15
  • 25
Nighil
  • 4,099
  • 7
  • 30
  • 56