{"id":2703,"date":"2010-01-06T11:49:00","date_gmt":"2010-01-06T11:49:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudio\/2010\/01\/06\/getting-information-about-objects-types-and-members-with-expression-trees\/"},"modified":"2022-10-17T15:07:24","modified_gmt":"2022-10-17T22:07:24","slug":"getting-information-about-objects-types-and-members-with-expression-trees","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/getting-information-about-objects-types-and-members-with-expression-trees\/","title":{"rendered":"Getting Information About Objects, Types, and Members with Expression Trees"},"content":{"rendered":"<p>Starting with C# 3.0 and Visual Studio 2008, you can use expression trees to get information about objects, types, and members. In this post I\u2019m going to show some examples and explain what benefits you can get by using this technique. If you are not familiar with expression trees, I would recommend reading Charlie Calvert\u2019s blog post <a href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkID=153998\">Expression Tree Basics<\/a> first.<\/p>\n<p>Let\u2019s start with a simple task. Assume that you want to print the name of a field or a property next to its value. For example, imagine that you have the following class.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:52ca311e-9240-4fbd-a61d-a86da0b75692\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>public class SampleClass\n{\npublic string SomeField = &#8220;Test&#8221;;\n}<\/div>\n<\/div>\n<\/div>\n<p>Of course, there is a straightforward solution:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:f112d293-f59c-46f0-8890-2145252bc150\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>SampleClass sample = new SampleClass();\nConsole.WriteLine(&#8220;SomeField : {0}&#8221;, sample.SomeField);\n\/\/ Prints SomeField : Test<\/div>\n<\/div>\n<\/div>\n<p>The problem with the above code is that you use a string literal <span style=\"font-family: Courier New;\">SomeField<\/span>. Nothing guarantees that this is the real name of the field. You might type the name incorrectly or just accidentally specify the wrong name. Furthermore, if you rename your property to, say, <span style=\"font-family: Courier New;\">AnotherField<\/span>, it could be hard to find a string literal that represents its name.<\/p>\n<p>Here is how you can create a method that returns a property name by using expression trees, without using any string literals:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:73e04e2e-ddf2-48cd-9587-6d1f805787fb\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>public static string GetName&lt;T&gt;(Expression&lt;Func&lt;T&gt;&gt; e)\n{\nvar member = (MemberExpression)e.Body;\nreturn member.Member.Name;\n}<\/div>\n<\/div>\n<\/div>\n<p>To call this method, you need to give it a lambda expression, as shown below.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:058c041d-6fbb-47d5-8a1a-4ec1b2bacbc0\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>Console.WriteLine(&#8220;{0} : {1}&#8221;,\nGetName(() =&gt; sample.SomeField), sample.SomeField);\n\/\/ Also prints SomeField : Test<\/div>\n<\/div>\n<\/div>\n<p>Because of the lambda expression, you get not only compile-time error checking, but also full IntelliSense support when typing a member name. And if you rename a property, the compiler will find all the places where the property name is used. Or you can rely on refactoring tools to rename all the instances of the property for you.<\/p>\n<p>In fact, you can also use this method to get the name of the variable itself (which can be convenient for tracing and logging).<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:3022db8f-b6b0-49ed-8389-a48fcbd01e74\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>Console.WriteLine(&#8220;{0} : {1}&#8221;, GetName(() =&gt; sample), sample);\n\/\/Prints sample : SampleClass<\/div>\n<\/div>\n<\/div>\n<p>The only problem with using a lambda expression is that you need to ensure that the user passes the correct one. For example, the user of your method can pass a lambda expression like<span style=\"font-family: Courier New;\"> () =&gt; new SampleClass()<\/span>. Unfortunately, you can\u2019t get a compile check for this. So, when using a lambda expression, make sure that you really get the expression you expect. For example, like this:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:add18b32-5827-4a0b-8a24-2406a5b71418\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\n<p>public static string GetName&lt;T&gt;(Expression&lt;Func&lt;T&gt;&gt; e)\n{\nvar member = e.Body as MemberExpression;<\/p>\n<p>\/\/ If the method gets a lambda expression\n\/\/ that is not a member access,\n\/\/ for example, () =&gt; x + y, an exception is thrown.\nif (member != null)\nreturn member.Member.Name;\nelse\nthrow new ArgumentException(\n&#8220;&#8216;&#8221; + e +\n&#8220;&#8216;: is not a valid expression for this method&#8221;);\n}<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>One more scenario where expression trees can help you is getting information about members of a type. C# provides the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/58918ffs.aspx\">typeof<\/a> operator to get type information, but does not provide operators like <b>memberof<\/b> or <b>infoof<\/b>. You can use reflection methods such as <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.type.getfield.aspx\">Type.GetField()<\/a>, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.type.getmethod.aspx\">Type.GetMethod()<\/a>, and so on, but then you have to use string literals again.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:2ce34047-6ffc-41d6-af96-1dd199e8f462\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\n<p>\/\/ By using typeof operator, you can get type information\n\/\/ without using string literals.\nType type = typeof(SampleClass);<\/p>\n<p>\/\/ But to get information about a member by using reflection,\n\/\/ you have to rely on string literals.\nFieldInfo fieldInfo = type.GetField(&#8220;SomeField&#8221;);<\/p>\n<p>Console.WriteLine(fieldInfo);\n\/\/ Prints System.String SomeField<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>The problem gets worse if you have overloaded methods in your class.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:f60cf92a-7691-4406-afd2-53e956524b3b\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>public class SampleClass\n{\npublic string SomeField = &#8220;Test&#8221;;\npublic void SomeMethod() { }\npublic void SomeMethod(string arg) { }\n}<\/div>\n<\/div>\n<\/div>\n<p>In this case, you need to specify a method and also its parameters.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:c91636c7-839e-484d-b679-b3526ce750fe\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>MethodInfo methodInfo = type.GetMethod(\n&#8220;SomeMethod&#8221;, new Type[] { typeof(String) });\nConsole.WriteLine(methodInfo);\n\/\/ Prints Void SomeMethod(System.String)<\/div>\n<\/div>\n<\/div>\n<p>Now you have more ways to get yourself into trouble. In addition to explicitly specifying the name of your method, you\u2019ve also specified the number and types of its parameters. So any changes in the method signature can affect the behavior of your program, and the compiler will not detect it.<\/p>\n<p>With expression trees you can get the same information without using string literals, and also get the compiler to check whether the member you need exists. Furthermore, all you need to do to get a necessary method overload is provide an example of the method usage within a lambda expression. Thanks to Mads Torgersen, a Visual Studio Program Manager, for providing the following code example.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:9d8a0efd-ba0e-4311-a4e6-5cc07a0aa7b2\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\n<p>public static MemberInfo MemberOf&lt;T&gt;(Expression&lt;Func&lt;T&gt;&gt; e)\n{\nreturn MemberOf(e.Body);\n}<\/p>\n<p>\/\/ We need to add this overload to cover scenarios\n\/\/ when a method has a void return type.\npublic static MemberInfo MemberOf(Expression&lt;Action&gt; e)\n{\nreturn MemberOf(e.Body);\n}<\/p>\n<p>private static MemberInfo MemberOf(Expression body)\n{\n{\nvar member = body as MemberExpression;\nif (member != null) return member.Member;\n}<\/p>\n<p>{\nvar method = body as MethodCallExpression;\nif (method != null) return method.Method;\n}<\/p>\n<p>throw new ArgumentException(\n&#8220;&#8216;&#8221; + body + &#8220;&#8216;: not a member access&#8221;);\n}<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>Now you can use the <span style=\"font-family: Courier New;\">MemberOf<\/span> method for all kinds of scenarios, for both instance and static members.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:c570dfe0-1971-4146-ac0c-6bb02e701c74\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\n<p>Console.WriteLine(MemberOf(() =&gt; sample.SomeField));\n\/\/ Prints System.String SomeField<\/p>\n<p>\/\/ To choose a particular method overload,\n\/\/ you simply show the usage of the method.\nConsole.WriteLine(MemberOf(() =&gt; sample.SomeMethod(&#8220;Test&#8221;)));\n\/\/ Prints Void SomeMethod(System.String)<\/p>\n<p>Console.WriteLine(MemberOf(() =&gt; sample.SomeMethod()));\n\/\/ Prints Void SomeMethod()<\/p>\n<p>Console.WriteLine(MemberOf(() =&gt; Console.Out));\n\/\/ Prints System.IO.TextWriter Out<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>I want to repeat that this functionality is already available in C# 3.0 and .NET Framework 3.5. If you want to know how expression trees are extended in .NET Framework 4, take a look at one of my previous posts: <a href=\"https:\/\/review.learn.microsoft.com\/en-us\/archive\/blogs\/csharpfaq\/generating-dynamic-methods-with-expression-trees-in-visual-studio-2010?branch=main\">Generating Dynamic Methods with Expression Trees in Visual Studio 2010<\/a>.<\/p>\n<p><strong>Update<\/strong><\/p>\n<p>See also a\u00a0follow-up post: <a href=\"https:\/\/review.learn.microsoft.com\/en-us\/archive\/blogs\/csharpfaq\/how-can-i-get-objects-and-property-values-from-expression-trees?branch=main\">How can I get objects and property values from expression trees?<\/a><\/p>\n<p><img width=\"1\" height=\"1\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Starting with C# 3.0 and Visual Studio 2008, you can use expression trees to get information about objects, types, and members. In this post I\u2019m going to show some examples and explain what benefits you can get by using this technique. If you are not familiar with expression trees, I would recommend reading Charlie Calvert\u2019s [&hellip;]<\/p>\n","protected":false},"author":13,"featured_media":255385,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[155],"tags":[3,5],"class_list":["post-2703","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-visual-studio","tag-net-framework","tag-csharp"],"acf":[],"blog_post_summary":"<p>Starting with C# 3.0 and Visual Studio 2008, you can use expression trees to get information about objects, types, and members. In this post I\u2019m going to show some examples and explain what benefits you can get by using this technique. If you are not familiar with expression trees, I would recommend reading Charlie Calvert\u2019s [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/2703","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=2703"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/2703\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/255385"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=2703"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=2703"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=2703"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}