{"id":9143,"date":"2024-12-09T16:10:33","date_gmt":"2024-12-09T15:10:33","guid":{"rendered":"https:\/\/solidt.eu\/site\/?p=9143"},"modified":"2024-12-09T16:10:35","modified_gmt":"2024-12-09T15:10:35","slug":"convert-linq-expression-to-readable-string","status":"publish","type":"post","link":"https:\/\/solidt.eu\/site\/convert-linq-expression-to-readable-string\/","title":{"rendered":"Convert LINQ expression to readable string"},"content":{"rendered":"\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"csharp\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">using System;\nusing System.Linq.Expressions;\nusing System.Text;\n\npublic static class ExpressionExtensions\n{\n    public static string ToReadableString(this Expression expression)\n    {\n        if (expression == null) return string.Empty;\n        var builder = new StringBuilder();\n        BuildReadableString(expression, builder);\n        return builder.ToString();\n    }\n\n    private static void BuildReadableString(Expression expression, StringBuilder builder)\n    {\n        switch (expression)\n        {\n            case LambdaExpression lambda:\n                BuildReadableString(lambda.Body, builder);\n                break;\n\n            case BinaryExpression binary:\n                builder.Append(\"(\");\n                BuildReadableString(binary.Left, builder);\n                builder.Append($\" {GetOperator(binary.NodeType)} \");\n                BuildReadableString(binary.Right, builder);\n                builder.Append(\")\");\n                break;\n\n            case MemberExpression member:\n                builder.Append(member.Member.Name);\n                break;\n\n            case ParameterExpression parameter:\n                builder.Append(parameter.Name);\n                break;\n\n            case ConstantExpression constant:\n                builder.Append(constant.Value);\n                break;\n\n            case MethodCallExpression methodCall:\n                builder.Append(methodCall.Method.Name);\n                builder.Append(\"(\");\n                for (int i = 0; i &lt; methodCall.Arguments.Count; i++)\n                {\n                    BuildReadableString(methodCall.Arguments[i], builder);\n                    if (i &lt; methodCall.Arguments.Count - 1)\n                        builder.Append(\", \");\n                }\n                builder.Append(\")\");\n                break;\n\n            default:\n                builder.Append(expression.ToString());\n                break;\n        }\n    }\n\n    private static string GetOperator(ExpressionType nodeType) =>\n        nodeType switch\n        {\n            ExpressionType.Add => \"+\",\n            ExpressionType.Subtract => \"-\",\n            ExpressionType.Multiply => \"*\",\n            ExpressionType.Divide => \"\/\",\n            ExpressionType.AndAlso => \"&amp;&amp;\",\n            ExpressionType.OrElse => \"||\",\n            ExpressionType.Equal => \"==\",\n            ExpressionType.NotEqual => \"!=\",\n            ExpressionType.LessThan => \"&lt;\",\n            ExpressionType.LessThanOrEqual => \"&lt;=\",\n            ExpressionType.GreaterThan => \">\",\n            ExpressionType.GreaterThanOrEqual => \">=\",\n            _ => nodeType.ToString()\n        };\n}\n<\/pre><\/div>\n\n\n\n<p>With expanded methods:<\/p>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"csharp\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">using System;\nusing System.Linq.Expressions;\nusing System.Text;\n\npublic static class ExpressionExtensions\n{\n    public static string ToReadableString(this Expression expression)\n    {\n        if (expression == null) return string.Empty;\n        var builder = new StringBuilder();\n        BuildReadableString(expression, builder);\n        return builder.ToString();\n    }\n\n    private static void BuildReadableString(Expression expression, StringBuilder builder)\n    {\n        switch (expression)\n        {\n            case LambdaExpression lambda:\n                BuildReadableString(lambda.Body, builder);\n                break;\n\n            case BinaryExpression binary:\n                builder.Append(\"(\");\n                BuildReadableString(binary.Left, builder);\n                builder.Append($\" {GetOperator(binary.NodeType)} \");\n                BuildReadableString(binary.Right, builder);\n                builder.Append(\")\");\n                break;\n\n            case MemberExpression member:\n                builder.Append(member.Member.Name);\n                break;\n\n            case ParameterExpression parameter:\n                builder.Append(parameter.Name);\n                break;\n\n            case ConstantExpression constant:\n                builder.Append(constant.Value);\n                break;\n\n            case MethodCallExpression methodCall:\n                if (methodCall.Method.DeclaringType == typeof(Enumerable) ||\n                    methodCall.Method.DeclaringType == typeof(Queryable))\n                {\n                    \/\/ LINQ-methoden zoals Where, Any, etc.\n                    TranslateLinqMethod(methodCall, builder);\n                }\n                else\n                {\n                    \/\/ Andere method calls\n                    builder.Append(methodCall.Method.Name);\n                    builder.Append(\"(\");\n                    for (int i = 0; i &lt; methodCall.Arguments.Count; i++)\n                    {\n                        BuildReadableString(methodCall.Arguments[i], builder);\n                        if (i &lt; methodCall.Arguments.Count - 1)\n                            builder.Append(\", \");\n                    }\n                    builder.Append(\")\");\n                }\n                break;\n\n            default:\n                builder.Append(expression.ToString());\n                break;\n        }\n    }\n\n    private static void TranslateLinqMethod(MethodCallExpression methodCall, StringBuilder builder)\n    {\n        switch (methodCall.Method.Name)\n        {\n            case \"Where\":\n                builder.Append(\"Filter items where \");\n                var lambda = (LambdaExpression)((UnaryExpression)methodCall.Arguments[1]).Operand;\n                BuildReadableString(lambda.Body, builder);\n                break;\n\n            case \"Any\":\n                builder.Append(\"Exists where \");\n                var anyLambda = (LambdaExpression)((UnaryExpression)methodCall.Arguments[1]).Operand;\n                BuildReadableString(anyLambda.Body, builder);\n                break;\n\n            case \"All\":\n                builder.Append(\"All items satisfy \");\n                var allLambda = (LambdaExpression)((UnaryExpression)methodCall.Arguments[1]).Operand;\n                BuildReadableString(allLambda.Body, builder);\n                break;\n\n            case \"Select\":\n                builder.Append(\"Select \");\n                var selectLambda = (LambdaExpression)((UnaryExpression)methodCall.Arguments[1]).Operand;\n                BuildReadableString(selectLambda.Body, builder);\n                break;\n\n            case \"OrderBy\":\n                builder.Append(\"Order by \");\n                var orderByLambda = (LambdaExpression)((UnaryExpression)methodCall.Arguments[1]).Operand;\n                BuildReadableString(orderByLambda.Body, builder);\n                break;\n\n            case \"OrderByDescending\":\n                builder.Append(\"Order by descending \");\n                var orderByDescLambda = (LambdaExpression)((UnaryExpression)methodCall.Arguments[1]).Operand;\n                BuildReadableString(orderByDescLambda.Body, builder);\n                break;\n\n            default:\n                builder.Append(methodCall.Method.Name);\n                builder.Append(\"(\");\n                for (int i = 0; i &lt; methodCall.Arguments.Count; i++)\n                {\n                    BuildReadableString(methodCall.Arguments[i], builder);\n                    if (i &lt; methodCall.Arguments.Count - 1)\n                        builder.Append(\", \");\n                }\n                builder.Append(\")\");\n                break;\n        }\n    }\n\n    private static string GetOperator(ExpressionType nodeType) =>\n        nodeType switch\n        {\n            ExpressionType.Add => \"+\",\n            ExpressionType.Subtract => \"-\",\n            ExpressionType.Multiply => \"*\",\n            ExpressionType.Divide => \"\/\",\n            ExpressionType.AndAlso => \"&amp;&amp;\",\n            ExpressionType.OrElse => \"||\",\n            ExpressionType.Equal => \"==\",\n            ExpressionType.NotEqual => \"!=\",\n            ExpressionType.LessThan => \"&lt;\",\n            ExpressionType.LessThanOrEqual => \"&lt;=\",\n            ExpressionType.GreaterThan => \">\",\n            ExpressionType.GreaterThanOrEqual => \">=\",\n            _ => nodeType.ToString()\n        };\n}\n<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"<p>With expanded methods:<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-9143","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/9143","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/comments?post=9143"}],"version-history":[{"count":1,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/9143\/revisions"}],"predecessor-version":[{"id":9144,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/9143\/revisions\/9144"}],"wp:attachment":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/media?parent=9143"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/categories?post=9143"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/tags?post=9143"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}