简体   繁体   中英

Reading method values at runtime using reflection (+hack)?

Brief:

We have a C# method which accept parameters.

inside of that method we need to add Sql parameters (according to the method parameters).

It actually looks like this : http://i.stack.imgur.com/QP1y2.jpg (to enlarge) 在此输入图像描述

Please notice

I can write a class which will have all the method arguments. But then , I will have to create a class container for each SP ( and we have a lot).

Ok lets continue.

I was thinking to myself : " WHY should I insert each param manually - If I already have its : name , type , value in the method param ? I don't want to do this , maybe reflection will do this for me" ( lets leave for now the conversion for int <->DbType.Int32 )

But I encountered a problem. it is not possible reading values using reflection.

However , I did managed to read values via reflection with a hack.

1) I did this example: ( simulation to the 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 the DB class ( to simulate the AddInParameter to see if im getting values)

class myDB
{
    public void AddInParameter(string name, DbType dbt, object val)
    {
        Console.WriteLine("name=" + name + "    " + "DbType=" + dbt + "    " + "object val=" + val);
    }
}

And it is working :

I executed the method with :

MyMethod(1, "2", DateTime.Now);

And the output 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 fine.

the C# Question

How can I get over this hack :

 var hack = new {AddressId, countryId, dt};  //  the method arguments names

In my sample I wrote it hard coded.

The reflection method GetValue is working only because of this line.

Is there anything I can do to add on run-time the method arguments name as a property , so I will be able to do :

 foreach(PropertyInfo pi in SOMETHING.GetType().GetProperties()) 
   {
   }

Please consider this question as ac# question and not ORM question.

Also , If you want to play with running sample code ( just paste in console proj) : http://jsbin.com/azicut/1/edit

Does this provide some relief?

Do this 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 the parameter for each call.

AddWithValue at least will save you from writing type name.

 command.Parameters.AddWithValue("@demographics", demoXml);

But also you really shouln't pass that much parameter to a function. A simple DTO class can make your code much more readable. If I am not mistaken you are looking something like pyhton's locals ( Need something like locals in python ) which gives you local variables of function as key-value pair and you can't do this in c# as far as i know.

or you simple do not pass all variables you just can pass a Dictionary<string,object> and add key values to SqlParameter

i'm not familiar with the workings of c# and .net, but if this was java, i would say:

store the current parameters into an arraylist or map

you could either have 3 arraylists, one for each of the parameters that go into the addInParameters method call, or a map with all the values included in it (the type parameter would need to have some duplication as it does now)

use the array list as the only parameter in the insert/update methods use a for loop so that the AddInParameter call is only written once, and the parameters are like (array1[0], array2[0], array3[0]) rather than the actual values.

in php you could use associative arrays, does .net have associative arrays?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM