Utilアプリケーションフレームワーク共通操作クラス(12):Lambda式共通操作クラス(3)

9944 ワード

今日、単純なクエリーを開発したところ、私のLambda操作クラスのGetValueメソッドでは、クエリーの結果が間違っているほど、列挙タイプ値が正しく取得されていないことがわかりました.
エラーをキャプチャするためにいくつかのユニットテストを追加しました.コードは以下の通りです.
     /// <summary>
        ///   /// </summary>
 [TestMethod] public void TestGetValue_Enum() { var test1 = new Test1(); test1.NullableEnumValue = LogType.Error; // , 
            Expression<Func<Test1, bool>> expression = test => test.EnumValue == LogType.Debug; Assert.AreEqual( LogType.Debug.Value(), Lambda.GetValue( expression ) ); // , 
            expression = test => test.EnumValue == test1.NullableEnumValue; Assert.AreEqual( LogType.Error, Lambda.GetValue( expression ) ); // , 
            expression = test => test.NullableEnumValue == LogType.Debug; Assert.AreEqual( LogType.Debug, Lambda.GetValue( expression ) ); // , 
            expression = test => test.NullableEnumValue == test1.NullableEnumValue; Assert.AreEqual( LogType.Error, Lambda.GetValue( expression ) ); // , null
            test1.NullableEnumValue = null; expression = test => test.NullableEnumValue == test1.NullableEnumValue; Assert.AreEqual( null, Lambda.GetValue( expression ) ); }

ユニットテストはBugを取得することに成功し、私はLambda操作クラスを開き、GetValueメソッドを修正する準備をしています.コードはUtilアプリケーションフレームワーク共通操作クラス(8):Lambda式共通操作クラス(2)を参照してください.
GetValueの乱雑なコードに直面して、私はすぐに手がつけられないと感じて、それを徹底的に再構築しなければなりません.
私も以前Lambda式解析のコードや文章を見たことがありますが、基本的にはNodeTypeを使って判断しています.私がずっとこの方法を使っていないのは、NodeTypeの数が膨大で、複数のNodeTypeが同じExpressionタイプに変換される可能性があるからです.私は当時、switchでNodeTypeの仕事量が大きすぎると判断したので、Asを直接特定の式に変換して、空の値かどうかを判断しました.
私はこのパクリ方法を盲猫が死んだネズミにぶつかったと呼んで、主にユニットテストに頼って需要を捕獲して、ブレークポイントのデバッグを通じて、私はどの特定の表現式に変換するかを知ることができます.この方法は前期には有効に見え,NodeTypeを判断するコードよりも少なかったが,式の使い方が千差万別で負担が重くなり,メンテナンスができなくなった.
GetValueメソッドを徹底的に再構築するためには、式解析の知識を補う必要があります.オープンソースフレームワークlinq 2 dbを開き、彼がどのように解析したのかをよく観察します.ようやく目鼻が見えてきて、NodeTypeで再帰判断.
私は以前はNodeTypeを使って判断することしか知らなかったが、再帰的な方法を採用すべきだとは知らなかった.
GetValueを再構築しました.コードは以下の通りです.
     /// <summary>
        ///  , :t => t.Name == "A",  A /// </summary>
        /// <param name="expression"> , :t => t.Name == "A"</param>
        public static object GetValue( Expression expression ) { if ( expression == null ) return null; switch ( expression.NodeType ) { case ExpressionType.Lambda: return GetValue( ( (LambdaExpression)expression ).Body ); case ExpressionType.Convert: return GetValue( ( (UnaryExpression)expression ).Operand ); case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.GreaterThan: case ExpressionType.LessThan: case ExpressionType.GreaterThanOrEqual: case ExpressionType.LessThanOrEqual: return GetValue( ( (BinaryExpression)expression ).Right ); case ExpressionType.Call: return GetValue( ( (MethodCallExpression)expression ).Arguments.FirstOrDefault() ); case ExpressionType.MemberAccess: return GetMemberValue( (MemberExpression)expression ); case ExpressionType.Constant: return GetConstantExpressionValue( expression ); } return null; } /// <summary>
        ///   /// </summary>
        private static object GetMemberValue( MemberExpression expression ) { if ( expression == null ) return null; var field = expression.Member as FieldInfo; if ( field != null ) { var constValue = GetConstantExpressionValue( expression.Expression ); return field.GetValue( constValue ); } var property = expression.Member as PropertyInfo; if ( property == null ) return null; var value = GetMemberValue( expression.Expression as MemberExpression ); return property.GetValue( value ); } /// <summary>
        ///   /// </summary>
        private static object GetConstantExpressionValue( Expression expression ) { var constantExpression = (ConstantExpression)expression; return constantExpression.Value; }

すべてのテストを実行し、すべて合格し、前の機能に影響がないことを示します.これは自動化回帰テストの威力であり、ユニットテストがなければ、私はこれらのコードを再構築する勇気がありません.また、バグを修正するにはTDD方式を採用し、一度に修復することができ、永遠に後患を絶ち、あなたが持つ価値があります.
同時に、私は他の類似のコードを再構築して、もう貼らないで、今度ソースコードを発行する時、興味があれば見てもいいです.
   .Netアプリケーションフレームワーク交流QQ群:386092459、興味のある友人を歓迎して討論に参加します.
ご注目ありがとうございます.私のブログアドレス:http://www.cnblogs.com/xiadao521/