简体   繁体   English

如何在实例方法中使用反射

[英]How to use Reflection with instance methods

If i create the following method concerning transaction : 如果我创建以下有关事务的方法:

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

I want to ask three questions : 我想问三个问题:

1-if one of my internal methods failed to insert before } Does the connection and the transaction disposed and closed automatically or not ?I mean should i call the following block of code : 1-如果我的内部方法之一未能在}之前插入}连接和事务是否自动释放和关闭?我的意思是我应该调用以下代码块:

tran.Dispose();
conn.Close();
conn.Dispose();

2-Could i invoke an instance method with its properties instead of fill the object and passing it as a parameter again ? 2-我可以用其属性调用实例方法,而不是填充对象并再次将其作为参数传递吗?

 object res = theMethod.Invoke(process, processParameters);

I mean : I want to use this(with its object state) because it's instance method: 我的意思是:我想使用this(及其对象状态),因为它是实例方法:

 public string InsertRequest(IfxConnection conn,IfxTransaction trans)

instead of this current method : 代替当前方法:

 public string InsertRequest(EnhancementRequest obj, IfxConnection conn,IfxTransaction trans)

3-Is the following code written well? 3-以下代码编写正确吗? I mean, no redundant steps and no logical errors.? 我的意思是,没有多余的步骤,也没有逻辑错误。

The code has some redundancies and some possible issues. 该代码具有一些冗余和一些可能的问题。

First of all if you are narrowing scope of connection and transaction objects with using statement, you don't need to call Dispose on any of these objects as using will take care of it for you. 首先,如果要通过using语句缩小连接和事务对象的范围,则无需在这些对象中的任何一个上调用Dispose,因为using会为您处理。

If your functions calling stored procedures are not handling database exceptions you should add try .. except aroung your transaction scope: 如果调用存储过程的函数未处理数据库异常,则应添加try ..,除非存在事务范围:

   using (IfxTransaction tran = conn.BeginTransaction())
   {
      try
      {
         // All db operations here
         tran.Commit();
      }
      catch(Exception e)
      {
         tran.Rollback();
         throw; // Or return error code
      }
   }

So effectively if some non-exception validation condition fails you just need to call trans.Rollback() and return your error code. 因此,如果某些非例外验证条件失败,则只需调用trans.Rollback()并返回错误代码即可。

Regarding your question 2 I would suggest adding generic call as your function parameter: 关于您的问题2,我建议添加泛型调用作为您的函数参数:

public static int Insert(Func<IfxConnection, IfxTransaction, object> callback)
{
   // ...
   object res = callback(conn, tran);
   // ...
}

In the code above I used generic delegate Func, you can call your insert function like this: 在上面我使用通用委托Func的代码中,您可以像这样调用插入函数:

Insert((conn, tran) =>
{
    // do something here with conn and tran and return object
});

Alternatively you can declare your own delegate signature which can be helpful if you plan to change it in the future: 另外,您可以声明自己的委托人签名,如果将来计划更改它,这将很有帮助:

public delegate object MyDelegateType(IfxConnection conn, IfxTransaction tran);

Then when calling insert just pass the object and method of your choice as an argument: 然后,在调用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);
    }
}

The method after some changes: 更改后的方法:

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

When calling this function just pass any instance method with matching signature as processMethod. 调用此函数时,只需将具有匹配签名的任何实例方法传递为processMethod。

Another suggestion is to change all functions to use the similar callback syntax and instead of passing string and object arguments, call the method directly as strong typing in this case gives more readability. 另一个建议是将所有函数更改为使用类似的回调语法,而不是传递字符串和对象参数,而应直接调用该方法,因为在这种情况下,强类型化可以提高可读性。

Regarding readability as you run of series of operations in a transaction and if either one fails, whole transaction needs to fail, it's better to reduce nested conditions and check for fail first (see above). 关于在事务中运行一系列操作时的可读性,如果任何一个失败,则整个事务都将失败,因此最好减少嵌套条件并首先检查失败(请参见上文)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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