如何通过实例方法使用反射
How to use Reflection with instance methods
如果我创建以下有关交易的方法:
public static int Insert(string processMethod, object[] processParameters, Type processType, object process, UserTransactionDTO transObj, string spPostConfirm, int toEmpNum,int confirmState)
{
int affectedRows = -7;
using (IfxConnection conn = new IfxConnection(ConfigurationManager.ConnectionStrings["crms"].ToString() + " Enlist=true;"))
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
using (IfxTransaction tran = conn.BeginTransaction())
{
if (!string.IsNullOrEmpty(processMethod))//business Method
{
processParameters[1] = conn;
processParameters[2] = tran;
MethodInfo theMethod = processType.GetMethod(processMethod, new[] { processParameters.First().GetType(), typeof(IfxConnection), typeof(IfxTransaction) });
object res = theMethod.Invoke(process, processParameters);
transObj.ValuesKey = res.ToString();
}
if (!string.IsNullOrEmpty(transObj.ValuesKey))
{
affectedRows = RunPreConfirm(transObj.TaskCode, transObj.UserStateCode, transObj.ValuesKey, conn, tran, confirmState);//sp_confirm
if (affectedRows != 1)
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -1;//Fail
}
affectedRows = InsertTrans(transObj, conn, tran);//MainTransaction --->df2usertrans
if (affectedRows == 1)//Success
{
if (!string.IsNullOrEmpty(spPostConfirm))
{
affectedRows = RunPostConfirm(spPostConfirm, transObj.ValuesKey, conn, tran);//sp_post_confirm
if (affectedRows != 0)
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -2;//Fail
}
}
affectedRows = RunAfterTrans(transObj.TaskCode, transObj.OldStatusCode, transObj, toEmpNum, conn, tran);//sp_after_trans
if (affectedRows != 1)
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -3;//Fail
}
tran.Commit();
tran.Dispose();
conn.Close();
conn.Dispose();
return 1;
}
else
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -1;//Fail
}
}
else
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -1;//Fail
}
}
}
return affectedRows;
}
我想请教三个问题:
1-如果我的内部方法之一未能在 }
之前插入,连接和事务是否自动处理和关闭?我的意思是我应该调用以下代码块:
tran.Dispose();
conn.Close();
conn.Dispose();
2-我可以调用实例方法及其属性,而不是填充对象并将其再次作为参数传递吗?
object res = theMethod.Invoke(process, processParameters);
我的意思是:
我想使用它(及其对象状态),因为它是实例方法:
public string InsertRequest(IfxConnection conn,IfxTransaction trans)
而不是当前的方法:
public string InsertRequest(EnhancementRequest obj, IfxConnection conn,IfxTransaction trans)
3-下面的代码写得好吗?我的意思是,没有多余的步骤,也没有逻辑错误。?
代码有一些冗余和一些可能的问题。
首先,如果您使用 using 语句缩小连接和事务对象的范围,则不需要对这些对象中的任何一个调用 Dispose,因为 using 会为您处理。
如果调用存储过程的函数不处理数据库异常,您应该添加 try .. except aroung 您的事务范围:
using (IfxTransaction tran = conn.BeginTransaction())
{
try
{
// All db operations here
tran.Commit();
}
catch(Exception e)
{
tran.Rollback();
throw; // Or return error code
}
}
如此有效,如果某些非异常验证条件失败,您只需要调用 trans.Rollback() 和 return 您的错误代码。
关于你的问题 2,我建议添加泛型调用作为你的函数参数:
public static int Insert(Func<IfxConnection, IfxTransaction, object> callback)
{
// ...
object res = callback(conn, tran);
// ...
}
在上面的代码中我使用了泛型委托 Func,你可以这样调用你的插入函数:
Insert((conn, tran) =>
{
// do something here with conn and tran and return object
});
或者,您可以声明自己的委托签名,如果您打算在将来更改它,这会很有帮助:
public delegate object MyDelegateType(IfxConnection conn, IfxTransaction tran);
然后在调用 insert 时将您选择的对象和方法作为参数传递:
public class SomeClass
{
public static object ProcessOnInsert(IfxConnection conn, IfxTransaction tran)
{
// do something here with conn and tran
}
public static int Insert(MyDelegateType callback)
// or
// public static int Insert(Func<IfxConnection,IfxTransaction,object> callback)
{
// ...
callback(conn, tran);
// ...
}
public static void RunInsert()
{
Insert(ProcessOnInsert);
}
}
修改后的方法:
public static int Insert(Func<IfxConnection, IfxTransaction, object> processMethod, UserTransactionDTO transObj, string spPostConfirm, int toEmpNum, int confirmState)
{
int affectedRows = -7;
using (IfxConnection conn = new IfxConnection(ConfigurationManager.ConnectionStrings["crms"].ToString() + " Enlist=true;"))
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
using (IfxTransaction tran = conn.BeginTransaction())
{
try
{
if (processMethod != null)//business Method
{
object res = processMethod(conn, tran);
transObj.ValuesKey = res.ToString();
}
if (string.IsNullOrEmpty(transObj.ValuesKey)) //Fail
{
tran.Rollback();
return -1;//Fail
}
affectedRows = RunPreConfirm(transObj.TaskCode, transObj.UserStateCode, transObj.ValuesKey, conn, tran, confirmState);//sp_confirm
if (affectedRows != 1)
{
tran.Rollback();
return -1;//Fail
}
affectedRows = InsertTrans(transObj, conn, tran);//MainTransaction --->df2usertrans
if (affectedRows != 1)//Fail
{
tran.Rollback();
return -1;//Fail
}
if (!string.IsNullOrEmpty(spPostConfirm))
{
affectedRows = RunPostConfirm(spPostConfirm, transObj.ValuesKey, conn, tran);//sp_post_confirm
if (affectedRows != 0)
{
tran.Rollback();
return -2;//Fail
}
}
affectedRows = RunAfterTrans(transObj.TaskCode, transObj.OldStatusCode, transObj, toEmpNum, conn, tran);//sp_after_trans
if (affectedRows != 1)
{
tran.Rollback();
return -3;//Fail
}
tran.Commit();
return 1;
}
catch
{
trans.Rollback();
throw;
}
}
}
return affectedRows;
}
调用此函数时,只需传递任何具有匹配签名的实例方法作为 processMethod。
另一个建议是更改所有函数以使用类似的回调语法,而不是传递字符串和对象参数,而是直接调用方法,因为强类型在这种情况下提供了更多的可读性。
关于交易中一系列操作 运行 的可读性,如果任何一个失败,整个交易都需要失败,最好减少嵌套条件并首先检查失败(见上文)。
如果我创建以下有关交易的方法:
public static int Insert(string processMethod, object[] processParameters, Type processType, object process, UserTransactionDTO transObj, string spPostConfirm, int toEmpNum,int confirmState)
{
int affectedRows = -7;
using (IfxConnection conn = new IfxConnection(ConfigurationManager.ConnectionStrings["crms"].ToString() + " Enlist=true;"))
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
using (IfxTransaction tran = conn.BeginTransaction())
{
if (!string.IsNullOrEmpty(processMethod))//business Method
{
processParameters[1] = conn;
processParameters[2] = tran;
MethodInfo theMethod = processType.GetMethod(processMethod, new[] { processParameters.First().GetType(), typeof(IfxConnection), typeof(IfxTransaction) });
object res = theMethod.Invoke(process, processParameters);
transObj.ValuesKey = res.ToString();
}
if (!string.IsNullOrEmpty(transObj.ValuesKey))
{
affectedRows = RunPreConfirm(transObj.TaskCode, transObj.UserStateCode, transObj.ValuesKey, conn, tran, confirmState);//sp_confirm
if (affectedRows != 1)
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -1;//Fail
}
affectedRows = InsertTrans(transObj, conn, tran);//MainTransaction --->df2usertrans
if (affectedRows == 1)//Success
{
if (!string.IsNullOrEmpty(spPostConfirm))
{
affectedRows = RunPostConfirm(spPostConfirm, transObj.ValuesKey, conn, tran);//sp_post_confirm
if (affectedRows != 0)
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -2;//Fail
}
}
affectedRows = RunAfterTrans(transObj.TaskCode, transObj.OldStatusCode, transObj, toEmpNum, conn, tran);//sp_after_trans
if (affectedRows != 1)
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -3;//Fail
}
tran.Commit();
tran.Dispose();
conn.Close();
conn.Dispose();
return 1;
}
else
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -1;//Fail
}
}
else
{
tran.Rollback();
tran.Dispose();//Dispose
conn.Close();
conn.Dispose();
return -1;//Fail
}
}
}
return affectedRows;
}
我想请教三个问题:
1-如果我的内部方法之一未能在 }
之前插入,连接和事务是否自动处理和关闭?我的意思是我应该调用以下代码块:
tran.Dispose();
conn.Close();
conn.Dispose();
2-我可以调用实例方法及其属性,而不是填充对象并将其再次作为参数传递吗?
object res = theMethod.Invoke(process, processParameters);
我的意思是: 我想使用它(及其对象状态),因为它是实例方法:
public string InsertRequest(IfxConnection conn,IfxTransaction trans)
而不是当前的方法:
public string InsertRequest(EnhancementRequest obj, IfxConnection conn,IfxTransaction trans)
3-下面的代码写得好吗?我的意思是,没有多余的步骤,也没有逻辑错误。?
代码有一些冗余和一些可能的问题。
首先,如果您使用 using 语句缩小连接和事务对象的范围,则不需要对这些对象中的任何一个调用 Dispose,因为 using 会为您处理。
如果调用存储过程的函数不处理数据库异常,您应该添加 try .. except aroung 您的事务范围:
using (IfxTransaction tran = conn.BeginTransaction())
{
try
{
// All db operations here
tran.Commit();
}
catch(Exception e)
{
tran.Rollback();
throw; // Or return error code
}
}
如此有效,如果某些非异常验证条件失败,您只需要调用 trans.Rollback() 和 return 您的错误代码。
关于你的问题 2,我建议添加泛型调用作为你的函数参数:
public static int Insert(Func<IfxConnection, IfxTransaction, object> callback)
{
// ...
object res = callback(conn, tran);
// ...
}
在上面的代码中我使用了泛型委托 Func,你可以这样调用你的插入函数:
Insert((conn, tran) =>
{
// do something here with conn and tran and return object
});
或者,您可以声明自己的委托签名,如果您打算在将来更改它,这会很有帮助:
public delegate object MyDelegateType(IfxConnection conn, IfxTransaction tran);
然后在调用 insert 时将您选择的对象和方法作为参数传递:
public class SomeClass
{
public static object ProcessOnInsert(IfxConnection conn, IfxTransaction tran)
{
// do something here with conn and tran
}
public static int Insert(MyDelegateType callback)
// or
// public static int Insert(Func<IfxConnection,IfxTransaction,object> callback)
{
// ...
callback(conn, tran);
// ...
}
public static void RunInsert()
{
Insert(ProcessOnInsert);
}
}
修改后的方法:
public static int Insert(Func<IfxConnection, IfxTransaction, object> processMethod, UserTransactionDTO transObj, string spPostConfirm, int toEmpNum, int confirmState)
{
int affectedRows = -7;
using (IfxConnection conn = new IfxConnection(ConfigurationManager.ConnectionStrings["crms"].ToString() + " Enlist=true;"))
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
using (IfxTransaction tran = conn.BeginTransaction())
{
try
{
if (processMethod != null)//business Method
{
object res = processMethod(conn, tran);
transObj.ValuesKey = res.ToString();
}
if (string.IsNullOrEmpty(transObj.ValuesKey)) //Fail
{
tran.Rollback();
return -1;//Fail
}
affectedRows = RunPreConfirm(transObj.TaskCode, transObj.UserStateCode, transObj.ValuesKey, conn, tran, confirmState);//sp_confirm
if (affectedRows != 1)
{
tran.Rollback();
return -1;//Fail
}
affectedRows = InsertTrans(transObj, conn, tran);//MainTransaction --->df2usertrans
if (affectedRows != 1)//Fail
{
tran.Rollback();
return -1;//Fail
}
if (!string.IsNullOrEmpty(spPostConfirm))
{
affectedRows = RunPostConfirm(spPostConfirm, transObj.ValuesKey, conn, tran);//sp_post_confirm
if (affectedRows != 0)
{
tran.Rollback();
return -2;//Fail
}
}
affectedRows = RunAfterTrans(transObj.TaskCode, transObj.OldStatusCode, transObj, toEmpNum, conn, tran);//sp_after_trans
if (affectedRows != 1)
{
tran.Rollback();
return -3;//Fail
}
tran.Commit();
return 1;
}
catch
{
trans.Rollback();
throw;
}
}
}
return affectedRows;
}
调用此函数时,只需传递任何具有匹配签名的实例方法作为 processMethod。
另一个建议是更改所有函数以使用类似的回调语法,而不是传递字符串和对象参数,而是直接调用方法,因为强类型在这种情况下提供了更多的可读性。
关于交易中一系列操作 运行 的可读性,如果任何一个失败,整个交易都需要失败,最好减少嵌套条件并首先检查失败(见上文)。