Reading method values at runtime using reflection (+ hack)?
Short information:
We have a C # method that takes parameters.
inside this method, we need to add Sql parameters (according to method parameters).
It actually looks like this: http://i.stack.imgur.com/QP1y2.jpg (for enlargement)
pay attention to
I can write a class that will have all the method arguments. But then I'll have to create a class container for each SP (and we have many).
Ok lets continue.
I thought to myself: " Why do I have to insert each parameter manually - if I already have: name
, type
, value
? Parameter method I do not want to do it, maybe thinking to do it for me" (let us now turn to the transformation of int <->DbType.Int32
)
But I ran into a problem. it is not the ability to read values using reflection.
However I did manage to read the values through reflection using a hack.
1) I made this example: (simulation for real scenario)
public static void MyMethod(int AddressId, string countryId, DateTime dt) //these are the arguments which need to be attached later
{
MethodBase mi = MethodInfo.GetCurrentMethod();
var hack = new {AddressId, countryId, dt}; //this is the HACK
var lstArguments = mi.GetParameters() //get the parameter name and types
.Select(p => new {
name = p.Name , type=p.GetType().Name
}).ToList();
List < dynamic > lstParamValues= new List < dynamic > ();
foreach(PropertyInfo pi in hack.GetType().GetProperties()) //get the value(!!!) of each param
{
lstParamValues.Add(pi.GetValue(hack, null));
}
dynamic dyn= myDBInstance; // get dynamic reference to the DB class instance (
for(int i = 0; i < lstArguments .Count; i++) //dynamically Invoke the method with param name+value.
{
dyn.AddInParameter(lstArguments [i].name, ((lstParamValues[i] is int) ? DbType.Int32 : DbType.String), lstParamValues[i]);
}
}
And there is a DB class (to simulate AddInParameter
, to see if im will get values)
class myDB
{
public void AddInParameter(string name, DbType dbt, object val)
{
Console.WriteLine("name=" + name + " " + "DbType=" + dbt + " " + "object val=" + val);
}
}
And it works:
I followed the method with:
MyMethod(1, "2", DateTime.Now);
And the result was:
name=AddressId DbType=Int32 object val=1
name=countryId DbType=String object val=2
name=dt DbType=String object val=05/02/2013 19:09:32
All perfectly.
C # question
How can I overcome this hack:
var hack = new {AddressId, countryId, dt}; // the method arguments names
In my example, I wrote it hardcoded.
The reflection method GetValue
only works because of this line.
Is there anything I can do to add, at runtime, the name of the method argument as a property, so I can do:
foreach(PropertyInfo pi in SOMETHING.GetType().GetProperties())
{
}
Please consider this question as a C # question, not an ORM question.
Also, if you want to play with the running example code (just paste in the console proj): http://jsbin.com/azicut/1/edit
source to share
Does this provide any relief?
Do it once (in the DAL ctor):
SqlParameter sqlCmdFTSindexWordOnceParam = sqlCmdFTSindexWordOnce.Parameters.Add("@sID", SqlDbType.Int);
sqlCmdFTSindexWordOnceParam.Direction = ParameterDirection.Input;
SqlParameter sqlCmdFTSindexWordOnceParam2 = sqlCmdFTSindexWordOnce.Parameters.Add("@sIDpar", SqlDbType.Int);
sqlCmdFTSindexWordOnceParam2.Direction = ParameterDirection.Input;
Then in the call:
sqlCmdFTSindexWordOnceParam.Value = wdc.sID; sqlCmdFTSindexWordOnceParam2.Value = wdc.sIDpar; sqlCmdFTSindexWordOnce.BeginExecuteNonQuery(callbackFTSindexWordOnce, sqlCmdFTSindexWordOnce);
Better performance than adding a parameter for each call.
source to share
AddWithValue
will at least keep you from typing the type name.
command.Parameters.AddWithValue("@demographics", demoXml);
But you don't really go to that parameter either. A simple DTO class can make your code more readable. If I'm not mistaken, you're looking at something like pyhton locals
( Need something like locals in python ) which gives you function local variables as a key-value pair, and you can't do that in C # as far as I know.
or you just don't pass all the variables you can only pass Dictionary<string,object>
and add the key values to the SqlParameter
source to share
I'm not familiar with how C # and .net works, but if it's java I would say:
save current parameters to arraylist or map
you can have 3 arraylists, one for each of the parameters that go into the call to the addInParameters method, or a map with all the values included in it (the type parameter should have some duplication as it is now)
use a list of arrays as the only parameter in the insert / update methods use a for loop so that the AddInParameter call is written only once and the parameters are similar (array1 [0], array2 [0], array3 [0]), not actual values.
in php you can use associative arrays, does the .net network have associative arrays?
source to share