{"id":644,"date":"2009-08-13T00:00:00","date_gmt":"2009-08-13T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/a-defense-of-reflection-in-net\/"},"modified":"2021-05-17T18:36:40","modified_gmt":"2021-05-17T18:36:40","slug":"a-defense-of-reflection-in-net","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/a-defense-of-reflection-in-net\/","title":{"rendered":"A Defense of Reflection in .NET"},"content":{"rendered":"<div id=\"PRETTY\">\n<h1>Introduction<\/h1>\n<p class=\"START\">Reflection is one of the great marvels of modern programming environments.&#160;&#160; Being able to store meta data about our code, and retrieve it at run time, opens up a world of possibilities.&#160;&#160; Many developers and software designers have embraced reflection and sing its praises, but reflection is not without its critics.<\/p>\n<p>Here we will explore some of the criticism of reflection, debunk some of the myths around its usage, and explore the benefits through some practical applications.<\/p>\n<h1>What&#8217;s Wrong With Reflection<\/h1>\n<p>There are various complaints and cautionary warnings against using reflection.&#160; Some of these are valid risks that we need to be&#160;aware of;&#160; others are wild tales based on early-adopters not understanding what they were using.&#160; Some are valid only in certain circumstances, or valid in all but special cases.&#160; Here we will explore some of these complaints.&#160;&#160; You should always be wary of a technology that is new or not well understood, but do not let that stand in the way of making appropriate use of technology.<\/p>\n<h2>Performance<\/h2>\n<p>Everyone knows that reflection is slow.&#160;&#160; The web is full of well meaning warnings that one should not use Reflection if you care about performance.&#160;&#160; Retrieving the meta-data slows your application down: One is often reading advice that, If you care about performance, you should&#160;never use reflection.&#160;&#160; <\/p>\n<p>This is a legitimate concern that should be taken seriously, but this is not a carte blanche reason not to ever use Reflection.<\/p>\n<p>While you should always worry about performance, you should not let performance worries keep you from making appropriate use of new technology.&#160;&#160; Do your own timing studies in your own environment. &#160;If there are performance issues, there are ways to minimize the performance impact.<\/p>\n<p>The DotNet framework itself uses reflection extensively.&#160; Reflection is being used whether we intend to or not.&#160;&#160; Take a look at the details in the <b>Machine.Config<\/b> file.&#160; Almost all that you see is providing details to open an Assembly and load a Type with Reflection to make the framework itself work.&#160; The DotNet framework is all about Reflection.<\/p>\n<p>If performance&#160;worries still nag you, there are tweaks that you can make in your own code to improve performance.<\/p>\n<p>If you are going to make repeated calls to the Properties of an object, cache the Properties in a Hash Table.&#160; Reference the hash table instead of repeated calls to <b>GetProperty<\/b> or <b>GetProperties<\/b>.&#160; The same is true for Methods, Types and Assemblies.<\/p>\n<p>Get comfortable with the <b>BindingFlags<\/b> enumeration.&#160; Always specify <b>BindingFlags<\/b>.&#160; Never use the <b>IgnoreCase<\/b> flag.&#160; Limit the searches to Public.&#160;&#160; Limit the searches to Static or Instance as appropriate.<\/p>\n<p>Don&#8217;t just assume that performance will suffer.&#160;&#160; Embrace Reflection, but test it.&#160;&#160; There are various profiling tools, such as Red Gate&#8217;s Ants Profiler.&#160;&#160; Use them to identify the true cause of a performance problem.&#160;&#160; If Reflection is the right tool, don&#8217;t ignore it simply because someone told you that it will be slow.&#160; If it turns out be too slow for you, there are ways to optimize its usage.<\/p>\n<h2>Security<\/h2>\n<p>Reflection, it is said, &#160;poses an unacceptable security risk.&#160;&#160; The essence of most designs that leverage Reflection also incorporate the process of dynamically discovering new code and executing it.&#160;&#160; This opens up&#160;a risk that malicious code will be executing and compromising the entire system.<\/p>\n<p>In the modern world of Malware and security threats, we are all concerned about security.&#160;&#160; The risk with Reflection is that malicious code may be substituted for your own code.&#160;&#160; Many reflective designs do, indeed, rely on loading new assemblies, discovering new types, and running discovered methods and properties on these new types.&#160; While this may lead many to steer clear of a reflective solution, don&#8217;t run scared.<\/p>\n<p>An intruder would need to physically place malicious code where your reflective code can find it.&#160;&#160; While this is not impossible, a good defense in depth design can mitigate this risk.&#160;&#160; Properly configured firewalls with processing servers behind the firewalls will help.&#160; Intrusion detection will alert administrators to servers that are being targeted, and properly patched servers will help eliminate known vulnerabilities.<\/p>\n<p>Code Access Security, properly configured, can also limit the access that reflective code has.&#160;&#160; With Code Access Security, individual assemblies can run with fewer rights than the user running the assembly.<\/p>\n<p>This article is not about configuring security settings but rather to assure you that there are counter measures to any security concern that you may have.<\/p>\n<h2>Confusion<\/h2>\n<p>Reflective code, so one hears, &#160;is very hard to follow.&#160;&#160; Developers new to the project will have difficulty learning the ropes.&#160; Anything that steepens the learning curve jeopardizes project time lines and should be avoided.&#160; If only a select group of developers can understand the reflective code then the project is overly dependent on this select group, and is doomed to fail.<\/p>\n<p>This is also not a very legitimate concern.&#160;&#160; If every design decision is based on what the least experienced programmer can readily understand, our designs will be severely limited.&#160;&#160; Reflective code can, and should, be isolated.&#160;&#160; Daily development should not be modifying this code.&#160;&#160; Daily development should use the reflective methods to simplify daily development tasks.&#160; <\/p>\n<p>We want our code to be easy to follow, and Reflective code is not always the most intuitive code to&#160;understand at first glance.&#160;&#160;&#160; Without a doubt the hard-coded option is easier to follow than the reflective version<\/p>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"TableContents\">Hard Coded<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"TableContents\">Reflective<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre class=\"lang:c# theme:vs2012\">public void MapData(IEmployee first, IEmployee second)\n{\n&#160;&#160;&#160; second.FirstName = first.FirstName;\n&#160;&#160;&#160; second.Address = first.Address;\n&#160;&#160;&#160; second.BranchLocation = first.BranchLocation;\n. . . \n}\n<\/pre>\n<pre class=\"lang:c# theme:vs2012\">public static void MapData(object sourceObject, \n&#160;&#160;&#160; object targetObject)\n{\n&#160;&#160;&#160; object[] value = new object[1];\n&#160;&#160;&#160; object[] param = new object[0];\n&#160;&#160;&#160; foreach (PropertyInfo propertyInfo \n&#160;&#160;&#160;&#160;&#160;&#160;&#160; in sourceObject.GetType().GetProperties())\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; PropertyInfo targetPropertyInfo = \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; targetObject.GetType().\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; GetProperty(propertyInfo.Name);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (targetPropertyInfo.CanWrite)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value[0] = propertyInfo.GetValue(sourceObject,\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; BindingFlags.Public, null, null, null);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; targetPropertyInfo.SetValue \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (targetObject, value,null);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160; }\n}\n&#160;\n<\/pre>\n<p>Anyone can look at the hard-coded version and immediately tell what is going on.&#160;&#160; The reflective version will probably take a senior developer a second&#160;look to figure out.<\/p>\n<p>However, the hard-coded version is tedious code.&#160; Depending on the number of properties being mapped, more and more errors are likely to be introduced.&#160; In the long run, this results in&#160; more code that has to be hand written.<\/p>\n<p>While the reflective code may be hard to follow, it does not need to be referenced very often to be useful.<\/p>\n<p>With the hard-coded implementation, you have to write a similar method for every type that you want to map.&#160; This is a tedious proposition indeed!&#160;&#160; With the reflective implementation, this one method can handle the process of mapping any object in your system.<\/p>\n<p>For the observant reader, this is far from the most optimized implementation for the reflective version.&#160; We will go over the reflective version in more detail later and discuss various ways to optimize.<\/p>\n<h1>Why Use Reflection?<\/h1>\n<h2>Developer Performance<\/h2>\n<p>As mentioned earlier, the hard coded version is often tedious, and tedious code is often error-prone.<\/p>\n<p>You can well imagine the potential for introducing bugs by having to iterate through, and explicitly set, each property in an object. This can quickly get out of hand.&#160;&#160; Bugs from assigning the wrong value to the wrong property are easy to introduce and difficult to track down.<\/p>\n<p>It is much easier to write a single line of code to handle the mapping and then move on to more important tasks&#160;such as&#160;implementing business logic and meeting deadlines.<\/p>\n<p>A call like <code>DataMapper.CopyTo (data, ui)<\/code> is easy to understand and quick to write.&#160;&#160; As long as the property names match and are of the same types, you don&#8217;t have to worry about missing any assignments.&#160;&#160; As a developer, you implement a series of rather simple properties to handle validation, and you don&#8217;t have to get bogged down in the details of the mapping logic.<\/p>\n<h2>Stability \/ Consistency<\/h2>\n<p>Not everyone will get reflective code right the first time, but this is the beauty of consistency.&#160; If the implementation that everyone is using is inefficient or has a logic problem, you have only to correct it in one place.&#160;&#160; If there are multiple hard coded implementations, some will, no doubt, be done as efficiently as possible.&#160;&#160; Some will,&#160;to be sure,&#160;be free from all logic problems, but at least some implementations will have problems that will need to be addressed.<\/p>\n<p>Reflective code is much easier to reuse.&#160;&#160; If the code is widely reused, then we have fewer places to correct when there is a problem found.<\/p>\n<p>This consistency improves the overall stability of the system.<\/p>\n<h1>Practical Applications<\/h1>\n<h2>Tweaking Performance <\/h2>\n<p>Performance is always a concern.&#160;&#160; There are some simple steps that we can take to eke &#160;the best performance out of our reflective code.<\/p>\n<p>Whenever you make a Reflection call, make it count.&#160; Cache the output so that it can be reused.&#160;&#160; Calls to <b>GetProperty<\/b>, <b>LoadAssembly<\/b> or <b>GetType<\/b> are expensive.&#160;&#160; If there is any chance that you are going to need a method or a property more than once, store the return value so that you can use it later without having to make the call again.&#160;&#160; <\/p>\n<p>This is also an example where multi threading can give you the perception of performance improvement.&#160;&#160; This proves to be a nice option for batch application and for business \/ data servers.&#160;&#160; This does not provide any benefit for the web UI, but can be very beneficial for a traditional windows application.<\/p>\n<h2>CopyTo<\/h2>\n<p><b>CopyTo<\/b> is the reflective MapData that we saw earlier.&#160;&#160; Let&#8217;s discuss some strategies to get the basic method ready for prime-time.&#160;&#160; As we stated earlier, we don&#8217;t want to throw away the return value of the <b>GetProperty<\/b> call.&#160;&#160; We also want to avoid calling <b>GetProperty<\/b> altogether when we are truly interested in every property.<\/p>\n<p>We start by checking to see if our collection of properties has already been loaded into a hash table.&#160; If they have, then we use this previously-loaded list.&#160;&#160; If not, we go ahead and load the details into the hash table.&#160; This will allow us to avoid the <b>GetProperty<\/b> calls altogether.&#160;&#160; If we are copying from one object to another of the same type, we dramatically reduce the number of reflection calls.&#160; If we call this method multiple times with the same set of objects, we reduce the reflective even more.<\/p>\n<p>Our caching logic could look similar to this:<\/p>\n<pre class=\"lang:c# theme:vs2012\">private Hashtable properties;\nprivate Hashtable Properties\n{\n&#160; get\n&#160; {\n&#160;&#160;&#160;&#160;&#160; if (properties == null)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; properties = new Hashtable();\n&#160;&#160;&#160;&#160;&#160; return properties;\n&#160; }\n}\n&#160;\nprivate void LoadProperties(object targetObject, Type targetType)\n{\n&#160;&#160;&#160; if (properties[targetType.FullName] != null)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; List&lt;PropertyInfo&gt; propertyList = new List&lt;PropertyInfo&gt;();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; PropertyInfo[] objectProperties = \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; targetType.GetProperties(BindingFlags.Public);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; foreach (PropertyInfo currentProperty in objectProperties)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; propertyList.Add(currentProperty);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; properties[targetObject] = propertyList;\n&#160;&#160;&#160; }\n}\n<\/pre>\n<p class=\"MsoNormal\">Here we first check to see if the Hash table already has a list of properties for our object.&#160;&#160; If it does then we have nothing to do.&#160;&#160; If not, we load the properties into a generic list to be added to the hash table.<\/p>\n<p class=\"MsoNormal\">Our optimized <b>CopyTo <\/b>function can now be rewritten as:<\/p>\n<pre class=\"lang:c# theme:vs2012\">&#160;public&#160; void CopyTo(object sourceObject, object targetObject)\n{\n&#160; object[] value = new object[1];\n&#160; Type sourceType = sourceObject.GetType();\n&#160; Type targetType = targetObject.GetType();\n&#160;\n&#160; LoadProperties(sourceObject, sourceType);\n&#160; LoadProperties(targetObject, targetType);\n&#160; List&lt;PropertyInfo&gt; sourcePoperties = \n&#160;&#160;&#160;&#160;&#160; Properties[sourceType.FullName] as List&lt;PropertyInfo&gt;;\n&#160; List&lt;PropertyInfo&gt; targetProperties = \n&#160;&#160;&#160;&#160;&#160; Properties[targetType.FullName] as List&lt;PropertyInfo&gt;;\n&#160; \n&#160; foreach (PropertyInfo sourceProperty in sourcePoperties)\n&#160; {\n&#160;&#160;&#160;&#160;&#160; PropertyInfo targetPropertyInfo = targetProperties.\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Find(delegate(PropertyInfo prop)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; { return prop.Name == sourceProperty.Name ; });\n&#160;&#160;&#160;&#160;&#160; if (sourceProperty.CanRead)\n&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (targetPropertyInfo.CanWrite)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value[0] = sourceProperty.GetValue(sourceObject,\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; BindingFlags.Public, null, null, null);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; targetPropertyInfo.SetValue\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (targetObject, value, null);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160; }\n&#160; }\n}\n<\/pre>\n<p class=\"MsoNormal\">The biggest change we have here is in the calls to the <b>LoadProperties<\/b> method.&#160;&#160; If the properties are already loaded, this will have no effect.&#160;&#160; If they are not, this method will load the properties for us.&#160; Once our properties are loaded into the hash table, we can safely pull them out of the generic list instead of making repeated calls to <b>GetProperties<\/b> or <b>GetProperty<\/b>.<\/p>\n<p class=\"MsoNormal\">Once we have our two properties, we make sure that the source can be read and that the target can be written to.&#160;&#160; Now we simply &#8220;get&#8221; the value from the source and &#8220;set&#8221; the value on the target.<\/p>\n<h2>MapDataToBusinessEntityCollection<\/h2>\n<p><b>MapDataToBusinessEntityCollection<\/b> is a generic Reflective method.&#160; We pass in the data-type for the objects to be mapped as a generic parameter along with a data reader.&#160;&#160; We use reflection to find the properties in this type and we use the meta data in the DataReader to find the fields.<\/p>\n<p>Whenever we find a field from the data reader that has a matching writable property in the generic type, we pull the value from the DataReader and assign it to a newly created object.&#160;&#160; Regardless of how many properties are in T, this method will map every property that has a matching field in the DataReader.&#160; Any properties that are not in the DataReader will be unmapped.&#160; Any fields in the data reader that do not have a matching property will be ignored.&#160;&#160; The validation logic is handled in the implementation of the properties in T.<\/p>\n<pre class=\"lang:c# theme:vs2012\">public static List&lt;T&gt; MapDataToBusinessEntityCollection&lt;T&gt;\n(IDataReader dr)\n&#160;&#160; where T : new()\n{\n&#160; Type businessEntityType = typeof (T);\n&#160; List&lt;T&gt; entitys = new List&lt;T&gt;();\n&#160; Hashtable hashtable = new Hashtable();\n&#160; PropertyInfo[] properties = businessEntityType.GetProperties();\n&#160; foreach (PropertyInfo info in properties)\n&#160; {\n&#160;&#160;&#160;&#160;&#160; hashtable[info.Name.ToUpper()] = info;\n&#160; }\n&#160; while (dr.Read())\n&#160; {\n&#160;&#160;&#160;&#160;&#160; T newObject = new T();\n&#160;&#160;&#160;&#160;&#160; for (int index = 0; index &lt; dr.FieldCount; index++)\n&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; PropertyInfo info = (PropertyInfo)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; hashtable[dr.GetName(index).ToUpper()];\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ((info != null) &amp;&amp; info.CanWrite)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; info.SetValue(newObject, dr.GetValue(index), null);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160; entitys.Add(newObject);\n&#160; }\n&#160; dr.Close();\n&#160; return entitys;\n}\n<\/pre>\n<h1>Timing Studies<\/h1>\n<p>To evaluate the performance implications of this approach, I set up a test-bed to perform my own timing studies.&#160;&#160; An ounce of testing is worth a pound of speculation. <\/p>\n<p>In my test-bed, I defined an object to encapsulate the Employee table in the NorthWinds database.&#160;&#160; I loaded this table with 100,000 records and timed how long it took to retrieve records using various methods.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/777-ADefen1.jpg\" alt=\"777-ADefen1.jpg\" \/><\/p>\n<p><strong>Hardcoded,<\/strong> is this case, is the worse way you can write a Hard-coded&#160;&#160;implementation, but it is also an approach that I have commonly seen followed.<\/p>\n<pre class=\"lang:c# theme:vs2012\">private void HardCoded()\n{\n&#160; System.DateTime start = DateTime.Now;\n&#160; System.Data.IDataReader dr = GetData(recordCount);\n&#160; while (dr.Read())\n&#160; {\n&#160;&#160;&#160;&#160;&#160; CustomTypes.Employees newEmployee = \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; new CustomTypes.Employees();\n&#160;&#160;&#160;&#160;&#160; newEmployee.Address = dr[\"Address\"].ToString();\n&#160;&#160;&#160;&#160;&#160; newEmployee.BirthDate = \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; DateTime.Parse(dr[\"BirthDate\"].ToString());\n&#160;&#160;&#160;&#160;&#160; newEmployee.City = dr[\"City\"].ToString();\n&#160;&#160;&#160;&#160;&#160; newEmployee.Country = dr[\"Country\"].ToString();\n&#160;&#160;&#160;&#160;&#160; newEmployee.EmployeeID = Int32.Parse(dr[\"EmployeeID\"].ToString());\n&#160;&#160;&#160;&#160;&#160; newEmployee.Extension = dr[\"Extension\"].ToString();\n&#160;&#160;&#160;&#160;&#160; newEmployee.FirstName = dr[\"FirstName\"].ToString();\n&#160;&#160;&#160;&#160;&#160; newEmployee.HireDate = DateTime.Parse(dr[\"HireDate\"].ToString());\n&#160;&#160;&#160;&#160;&#160; newEmployee.LastName = dr[\"LastName\"].ToString();\n&#160;&#160;&#160;&#160;&#160; newEmployee.PostalCode = dr[\"PostalCode\"].ToString();\n&#160;&#160;&#160;&#160;&#160; newEmployee.Region = dr[\"Region\"].ToString();\n&#160;&#160;&#160;&#160;&#160; newEmployee.ReportsTo = Int32.Parse(dr[\"ReportsTo\"].ToString());\n&#160;&#160;&#160;&#160;&#160; newEmployee.Title = dr[\"Title\"].ToString();\n&#160;&#160;&#160;&#160;&#160; newEmployee.TitleOfCourtesy = dr[\"TitleOfCourtesy\"].ToString();\n&#160;&#160;&#160;&#160;&#160; pgbHardCodedConversion.Increment(1);\n&#160; }\n&#160; dr.Close();\n&#160; System.DateTime stop = DateTime.Now;\n&#160; System.TimeSpan ts = new TimeSpan(stop.Ticks - start.Ticks);\n&#160; lblHardCodedConvertedTime.Text = \"Finished in \" \n+ ts.TotalMilliseconds + \" milliseconds\";\n}\n<\/pre>\n<p>This has several obvious problems, but since it has to be re coded for every data reader, it will often be done poorly.<\/p>\n<p>Reflective Singleton is the same method outlined above, but without caching the<b> PropertyInfo <\/b>objects.&#160;&#160; Comparing the Reflective Singleton and the <b>ReflectiveBatch<\/b> shows the benefits of caching the <b>PropertyInfo<\/b> objects.&#160;&#160; I believe this to be a dramatic improvement.<\/p>\n<p>Hard-Coded without Conversion is the same as the <strong>HardCoded<\/strong> implementation but skips the extra <strong>ToString<\/strong> and parsing operations which should never be performed anyway.<\/p>\n<p>So why is the Reflective Batch implementation faster than the hard-coded version?&#160;&#160; Indexing into the DataReader by Name is also a slow operation.&#160;&#160; The Reflective implementation avoids this costly lookup.<\/p>\n<p>Undoubtedly,&#160;caching the indexes into the DataReader will change the results.&#160;&#160; More properties in the test object will change the results, and there are&#160;probably more optimizations that could be done to the hard-coded implementation.<\/p>\n<p>All of this reinforces the need to test in your own environment.&#160; Test for yourself.&#160;&#160; You may be surprised that a reflective solution probably will not ruin performance, and it will shorten your time to market.<\/p>\n<h1>Conclusion<\/h1>\n<p>Do not shy away from Reflection or any other technology just because of warnings that you hear.&#160; Always verify that the warnings apply to your project.&#160;&#160; Often times, they will not.<\/p>\n<p>If you are worried about performance concerns, don&#8217;t blindly follow someone else&#8217;s opinion.&#160; Test it with your own application.<\/p>\n<p>Above all don&#8217;t be afraid to learn something new!<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>The trouble with making general rules about programming practices is that one can miss out on many benefits of of a framework by following them too literally in every context. Everyone knows that one should watch for performance problems and security issues with reflection. It doesn&#8217;t mean you shouldn&#8217;t it, it just means you must test carefully, monitor performance, and assess risks. Nick Harrison illustrates the theme with a practical example.&hellip;<\/p>\n","protected":false},"author":221853,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4229,4619],"coauthors":[],"class_list":["post-644","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-net-framework","tag-security"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/644","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221853"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=644"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/644\/revisions"}],"predecessor-version":[{"id":91133,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/644\/revisions\/91133"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=644"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=644"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=644"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=644"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}