使用反射(+ hack)在运行时读取方法值?

时间:2013-02-05 17:24:03

标签: c# .net reflection

简要说明:

我们有一个接受参数的C#方法。

在该方法内部我们需要添加Sql参数(根据方法参数)。

它看起来像这样: http://i.stack.imgur.com/QP1y2.jpg(放大) enter image description here

请注意

我可以编写一个包含所有方法参数的类。但是,我将不得不为每个SP创建一个类容器(我们有很多)。

好的,继续。

我在想:“为什么我应该insert each param manually - 如果我已经拥有:nametypevalue in方法参数?我不想这样做,也许反思会为我做这件事“(暂时离开int <->DbType.Int32的转换

但我遇到了一个问题。 可能使用反射读取值。

然而,我确实设法通过黑客反射来读取值。

1)我做了这个例子:(模拟真实场景)

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]);
}

}

还有数据库类模拟 AddInParameter以查看我是否获得了值)

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

它正在运作:

我用以下方法执行了该方法:

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

输出结果为:

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

一切都很好。

C#问题

我怎样才能克服这个黑客攻击:

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

在我的样本中,我写了硬编码。

反射方法GetValue仅适用于此行。

我可以做些什么来在运行时添加方法参数名称作为属性,所以我将能够做到:

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

请将此问题视为c#问题,而不是ORM问题。

另外,如果你想玩正在运行的示例代码(只需粘贴在控制台项目中):http://jsbin.com/azicut/1/edit

3 个答案:

答案 0 :(得分:0)

这能提供一些缓解吗?

这样做一次(在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;

然后在电话中:

sqlCmdFTSindexWordOnceParam.Value = wdc.sID;
sqlCmdFTSindexWordOnceParam2.Value = wdc.sIDpar;                                    
sqlCmdFTSindexWordOnce.BeginExecuteNonQuery(callbackFTSindexWordOnce, sqlCmdFTSindexWordOnce);

比为每个调用添加参数更好的性能。

答案 1 :(得分:0)

AddWithValue至少可以避免编写类型名称。

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

但是你真的不能把那么多参数传递给一个函数。一个简单的DTO类可以使您的代码更具可读性。如果我没弄错的话,你看起来像pyhton的localsNeed something like locals in python),它给你作为键值对的局部变量函数,据我所知你不能在c#中这样做。

或者你很简单,不传递你可以传递Dictionary<string,object>的所有变量并将关键值添加到SqlParameter

答案 2 :(得分:-3)

我不熟悉c#和.net的工作方式,但如果这是java,我会说:

将当前参数存储到arraylist或map

你可以有3个arraylists,一个用于进入addInParameters方法调用的每个参数,或者包含所有值的map(类型参数需要像现在一样重复)< / p>

使用数组列表作为插入/更新方法中的唯一参数 使用for循环以便AddInParameter调用只写一次,参数类似于(array1 [0],array2 [0],array3 [0])而不是实际值。

在php中你可以使用关联数组,.net是否有关联数组?