Cyotek Development Bloghttps://devblog.cyotek.com/tag/reflection/atom.xml2013-07-28T19:43:47ZUsing alternate descriptions for enumeration membersurn:uuid:d0efae35-6587-4d52-a621-78ec84205f7c2013-07-28T19:43:47Z2013-07-28T19:43:47Z<p>The last two articles (<a href="/post/creating-a-custom-typeconverter-part-1">here</a> and <a href="/post/creating-a-custom-typeconverter-part-2">here</a>) described
creating a custom type converter for converting units of
measurement.</p>
<p>However, what happens when you want to display or convert
to/from alternative representations? For example, consider the
enum below.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">internal</span> <span class="keyword">enum</span> Unit
<span class="symbol">{</span>
 cm<span class="symbol">,</span>
 mm<span class="symbol">,</span>
 pt<span class="symbol">,</span>
 px
<span class="symbol">}</span>
</pre>
</figure>
<p>Apart from the fact such an enum more than likely doesn't match
any coding standards you use, what happens when you want to
include percentages in the mix? Not many languages are going to
let you use % as a symbol name!</p>
<p>So we rewrite the enum to make more sense, in which case you
might have this:</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">internal</span> <span class="keyword">enum</span> Unit
<span class="symbol">{</span>
 Centimetre<span class="symbol">,</span>
 Millimetre<span class="symbol">,</span>
 Point<span class="symbol">,</span>
 Pixel<span class="symbol">,</span>
 Percent
<span class="symbol">}</span>
</pre>
</figure>
<figure class="screenshot" ><a href="https://images.cyotek.com/image/devblog/typeconv3-a.png" class="gallery" title="Using the actual enum member names doesn't seem like a good idea does it?" ><img src="https://images.cyotek.com/image/thumbnail/devblog/typeconv3-a.png" alt="Using the actual enum member names doesn't seem like a good idea does it?" decoding="async" loading="lazy" /></a><figcaption>Using the actual enum member names doesn't seem like a good idea does it?</figcaption></figure>
<p>Great! Except... your users want to see cm, px, % etc. Now what?</p>
<h2 id="the-manual-way">The manual way</h2>
<p>Well, you could create a function which takes a unit, and
manually checks the values and returns an appropriate value, for
example:</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">public</span> <span class="keyword">string</span> GetUnitSuffix<span class="symbol">(</span>Unit unit<span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">string</span> result<span class="symbol">;</span>

 <span class="keyword">switch</span> <span class="symbol">(</span>unit<span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">case</span> Unit<span class="symbol">.</span>Centimetre<span class="symbol">:</span>
 result <span class="symbol">=</span> <span class="string">&quot;cm&quot;</span><span class="symbol">;</span>
 <span class="keyword">break</span><span class="symbol">;</span>
 <span class="symbol">...</span>
 <span class="symbol">}</span>

 <span class="keyword">return</span> result<span class="symbol">;</span>
<span class="symbol">}</span>
</pre>
</figure>
<p>While this would certainly work, it means you have to duplicate
this code for every enum you wish to have alternate descriptions
for. Not to mention, should you add a new member to the enum,
you have to remember to update this function. More than likely,
you also want a sister version of this function which accepts
the string version, and returns the enum value.</p>
<h2 id="the-automatic-way">The automatic way</h2>
<p>A better way would be to tag each enum member with an
appropriate description, then you can use reflection to scan
your enum members and perform automatic to and from conversions.</p>
<p>In this example, I'm going to use the <code>DescriptionAttribute</code>
from the <code>System.ComponentModel</code> namespace, although depending
on what you're trying to do, a custom attribute may be better -
that's not exactly what this attribute was intended for!</p>
<p>First, decorate your enum with the attribute.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">internal</span> <span class="keyword">enum</span> Unit
<span class="symbol">{</span>
 <span class="symbol">[</span>Description<span class="symbol">(</span><span class="string">&quot;cm&quot;</span><span class="symbol">)</span><span class="symbol">]</span>
 Centimetre<span class="symbol">,</span>

 <span class="symbol">[</span>Description<span class="symbol">(</span><span class="string">&quot;mm&quot;</span><span class="symbol">)</span><span class="symbol">]</span>
 Millimetre<span class="symbol">,</span>

 <span class="symbol">[</span>Description<span class="symbol">(</span><span class="string">&quot;pt&quot;</span><span class="symbol">)</span><span class="symbol">]</span>
 Point<span class="symbol">,</span>

 <span class="symbol">[</span>Description<span class="symbol">(</span><span class="string">&quot;px&quot;</span><span class="symbol">)</span><span class="symbol">]</span>
 Pixel<span class="symbol">,</span>

 <span class="symbol">[</span>Description<span class="symbol">(</span><span class="string">&quot;%&quot;</span><span class="symbol">)</span><span class="symbol">]</span>
 Percent
<span class="symbol">}</span>
</pre>
</figure>
<p>Next add a couple of functions that will perform the conversion
of your enum to and from a string. With this in place you can
add new members, and, as long as you add your attribute to
them, the functions will automatically handle the new values.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">string</span> GetDescription<span class="symbol">(</span><span class="keyword">this</span> Unit value<span class="symbol">)</span>
<span class="symbol">{</span>
 FieldInfo field<span class="symbol">;</span>
 DescriptionAttribute attribute<span class="symbol">;</span>
 <span class="keyword">string</span> result<span class="symbol">;</span>

 field <span class="symbol">=</span> value<span class="symbol">.</span>GetType<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">.</span>GetField<span class="symbol">(</span>value<span class="symbol">.</span>ToString<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">)</span><span class="symbol">;</span>
 attribute <span class="symbol">=</span> <span class="symbol">(</span>DescriptionAttribute<span class="symbol">)</span>Attribute<span class="symbol">.</span>GetCustomAttribute<span class="symbol">(</span>field<span class="symbol">,</span> <span class="keyword">typeof</span><span class="symbol">(</span>DescriptionAttribute<span class="symbol">)</span><span class="symbol">)</span><span class="symbol">;</span>
 result <span class="symbol">=</span> attribute <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">?</span> attribute<span class="symbol">.</span>Description <span class="symbol">:</span> <span class="keyword">string</span><span class="symbol">.</span>Empty<span class="symbol">;</span>

 <span class="keyword">return</span> result<span class="symbol">;</span>
<span class="symbol">}</span>

<span class="keyword">public</span> <span class="keyword">static</span> Unit GetValue<span class="symbol">(</span><span class="keyword">string</span> value<span class="symbol">)</span>
<span class="symbol">{</span>
 Unit result<span class="symbol">;</span>

 result <span class="symbol">=</span> Unit<span class="symbol">.</span>None<span class="symbol">;</span>

 <span class="keyword">foreach</span> <span class="symbol">(</span>Unit id <span class="keyword">in</span> Enum<span class="symbol">.</span>GetValues<span class="symbol">(</span><span class="keyword">typeof</span><span class="symbol">(</span>Unit<span class="symbol">)</span><span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 FieldInfo field<span class="symbol">;</span>
 DescriptionAttribute attribute<span class="symbol">;</span>

 field <span class="symbol">=</span> id<span class="symbol">.</span>GetType<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">.</span>GetField<span class="symbol">(</span>id<span class="symbol">.</span>ToString<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">)</span><span class="symbol">;</span>
 attribute <span class="symbol">=</span> Attribute<span class="symbol">.</span>GetCustomAttribute<span class="symbol">(</span>field<span class="symbol">,</span> <span class="keyword">typeof</span><span class="symbol">(</span>DescriptionAttribute<span class="symbol">)</span><span class="symbol">)</span> <span class="keyword">as</span> DescriptionAttribute<span class="symbol">;</span>

 <span class="keyword">if</span> <span class="symbol">(</span>attribute <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> attribute<span class="symbol">.</span>Description <span class="symbol">==</span> value<span class="symbol">)</span>
 <span class="symbol">{</span>
 result <span class="symbol">=</span> id<span class="symbol">;</span>
 <span class="keyword">break</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>

 <span class="keyword">return</span> result<span class="symbol">;</span>
<span class="symbol">}</span>
</pre>
</figure>
<p>I choose to make the version that accepts the enum member as an
input parameter an extension method, that way I can call it like
this:</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">string</span> unitSuffix<span class="symbol">;</span>

unitSuffix <span class="symbol">=</span> <span class="keyword">this</span><span class="symbol">.</span>Unit<span class="symbol">.</span>GetDescription<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
</pre>
</figure>
<p>However, as the sister method accepts a string parameter, it
doesn't make sense to make this an extension, unless you want it
to appear on every single string variable you declare! So I just
revert back to the usual static calling convention.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
Unit unit<span class="symbol">;</span>

unit <span class="symbol">=</span> EnumExtensions<span class="symbol">.</span>GetValue<span class="symbol">(</span>stringValue<span class="symbol">.</span>Substring<span class="symbol">(</span>nonDigitIndex<span class="symbol">)</span><span class="symbol">)</span><span class="symbol">;</span>
</pre>
</figure>
<figure class="screenshot" ><a href="https://images.cyotek.com/image/devblog/typeconv3-b.png" class="gallery" title="Much better - the user sees the short form version, but the code uses the full name" ><img src="https://images.cyotek.com/image/thumbnail/devblog/typeconv3-b.png" alt="Much better - the user sees the short form version, but the code uses the full name" decoding="async" loading="lazy" /></a><figcaption>Much better - the user sees the short form version, but the code uses the full name</figcaption></figure><h2 id="using-generics">Using Generics</h2>
<p>While there's nothing wrong with the above methods, they could
still be improved upon. As it stands now, the methods are fixed
to a specific enum, so we can change them to use generics
instead, then they'll work for all enums.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">string</span> GetDescription<span class="symbol">&lt;</span>T<span class="symbol">&gt;</span><span class="symbol">(</span><span class="keyword">this</span> T value<span class="symbol">)</span>
 <span class="keyword">where</span> T <span class="symbol">:</span> <span class="keyword">struct</span>
<span class="symbol">{</span>
 FieldInfo field<span class="symbol">;</span>
 DescriptionAttribute attribute<span class="symbol">;</span>
 <span class="keyword">string</span> result<span class="symbol">;</span>

 field <span class="symbol">=</span> value<span class="symbol">.</span>GetType<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">.</span>GetField<span class="symbol">(</span>value<span class="symbol">.</span>ToString<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">)</span><span class="symbol">;</span>
 attribute <span class="symbol">=</span> <span class="symbol">(</span>DescriptionAttribute<span class="symbol">)</span>Attribute<span class="symbol">.</span>GetCustomAttribute<span class="symbol">(</span>field<span class="symbol">,</span> <span class="keyword">typeof</span><span class="symbol">(</span>DescriptionAttribute<span class="symbol">)</span><span class="symbol">)</span><span class="symbol">;</span>
 result <span class="symbol">=</span> attribute <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">?</span> attribute<span class="symbol">.</span>Description <span class="symbol">:</span> <span class="keyword">string</span><span class="symbol">.</span>Empty<span class="symbol">;</span>

 <span class="keyword">return</span> result<span class="symbol">;</span>
<span class="symbol">}</span>

<span class="keyword">public</span> <span class="keyword">static</span> T GetValue<span class="symbol">&lt;</span>T<span class="symbol">&gt;</span><span class="symbol">(</span><span class="keyword">string</span> value<span class="symbol">,</span> T defaultValue<span class="symbol">)</span>
<span class="symbol">{</span>
 T result<span class="symbol">;</span>

 result <span class="symbol">=</span> defaultValue<span class="symbol">;</span>

 <span class="keyword">foreach</span> <span class="symbol">(</span>T id <span class="keyword">in</span> Enum<span class="symbol">.</span>GetValues<span class="symbol">(</span><span class="keyword">typeof</span><span class="symbol">(</span>T<span class="symbol">)</span><span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 FieldInfo field<span class="symbol">;</span>
 DescriptionAttribute attribute<span class="symbol">;</span>

 field <span class="symbol">=</span> id<span class="symbol">.</span>GetType<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">.</span>GetField<span class="symbol">(</span>id<span class="symbol">.</span>ToString<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">)</span><span class="symbol">;</span>
 attribute <span class="symbol">=</span> Attribute<span class="symbol">.</span>GetCustomAttribute<span class="symbol">(</span>field<span class="symbol">,</span> <span class="keyword">typeof</span><span class="symbol">(</span>DescriptionAttribute<span class="symbol">)</span><span class="symbol">)</span> <span class="keyword">as</span> DescriptionAttribute<span class="symbol">;</span>

 <span class="keyword">if</span> <span class="symbol">(</span>attribute <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> attribute<span class="symbol">.</span>Description <span class="symbol">==</span> value<span class="symbol">)</span>
 <span class="symbol">{</span>
 result <span class="symbol">=</span> id<span class="symbol">;</span>
 <span class="keyword">break</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>

 <span class="keyword">return</span> result<span class="symbol">;</span>
<span class="symbol">}</span>
</pre>
</figure>
<h2 id="final-points">Final points</h2>
<p>Using reflection does have an overhead. If you expect to be
calling these methods a lot, you may wish to extend them yet
further in order to support caching the results in a dictionary
or other mechanism of your choice. That way, the first time a
new member is requested you perform the reflection lookup, and
thereafter just read the cache. I haven't done any benchmarking,
but it's probably safe to say a dictionary lookup (remember to
use <code>TryGetValue</code>!) is going to be a lot faster than a
reflection scan.</p>
<p>An example showing how the custom type converter from the
previous two articles updated to use the above technique is
available from the link below.</p>
<h2 id="update-history">Update History</h2>
<ul>
<li>2013-07-28 - First published</li>
<li>2020-11-21 - Updated formatting</li>
</ul>

<p><small>
All content <a href="https://devblog.cyotek.com/copyright-and-trademarks">Copyright (c) by Cyotek Ltd</a> or its respective writers. Permission to reproduce news and web log entries and other RSS feed content in unmodified form without notice is granted provided they are not used to endorse or promote any products or opinions (other than what was expressed by the author) and without taking them out of context. Written permission from the copyright owner must be obtained for everything else.<br />Original URL of this content is https://devblog.cyotek.com/post/using-alternate-descriptions-for-enumeration-members .
</small></p>Richard Mosshttps://www.cyotek.com/richard.moss@cyotek.comComparing the properties of two objects via Reflection and C#urn:uuid:5a0bc407-991b-4c81-b3b2-1e8c4af467a92010-11-05T23:33:54Z2010-11-05T23:18:48Z<p>As part of the refactoring I was doing to the load code for
crawler projects I needed a way of verifying that new code was
loading data correctly. As it would be extremely time consuming
to manually compare the objects, I used Reflection to compare
the different objects and their properties. This article briefly
describes the process and provides a complete helper function
you can use in your own projects.</p>
<p>This code is loosely based on <a href="https://stackoverflow.com/a/16132925/148962" rel="external nofollow noopener">a Stack Overflow question</a>,
but I have heavily modified and expanded the original concept.</p>
<h2 id="obtaining-a-list-of-properties">Obtaining a list of properties</h2>
<p>The ability to analyze assemblies and their component pieces is
directly built into the .NET Framework, and something I really
appreciate - I remember the nightmares of trying to work with
COM type libraries in Visual Basic many years ago!</p>
<p>The <code>Type</code> class represents a type declaration in your project,
such as a class or enumeration. You can either use the <code>GetType</code>
method of any object to get its underlying type, or use the
<code>typeof</code> keyword to access a type from its type name.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
Type typeA<span class="symbol">;</span>
Type typeB<span class="symbol">;</span>
<span class="keyword">int</span> value<span class="symbol">;</span>

value <span class="symbol">=</span> <span class="number">1</span><span class="symbol">;</span>

typeA <span class="symbol">=</span> value<span class="symbol">.</span>GetType<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
typeB <span class="symbol">=</span> <span class="keyword">typeof</span><span class="symbol">(</span><span class="keyword">int</span><span class="symbol">)</span><span class="symbol">;</span>
</pre>
</figure>
<p>Once you have a type, you can call the <code>GetProperties</code> method to
return a list of <code>PropertyInfo</code> objects representing the
available properties of the type. Several methods, including
<code>GetProperties</code>, accept an argument of <code>BindingFlags</code>, these
flags allow you to define the type of information return, such
as public members or instance members.</p>
<p>In this case, I want all public instance members which can be
read from and which are not included in a custom ignore list.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">foreach</span> <span class="symbol">(</span>PropertyInfo propertyInfo <span class="keyword">in</span> objectType<span class="symbol">.</span>GetProperties<span class="symbol">(</span>BindingFlags<span class="symbol">.</span>Public <span class="symbol">|</span> BindingFlags<span class="symbol">.</span>Instance<span class="symbol">)</span><span class="symbol">.</span>Where<span class="symbol">(</span>p <span class="symbol">=&gt;</span> p<span class="symbol">.</span>CanRead <span class="symbol">&amp;&amp;</span> <span class="symbol">!</span>ignoreList<span class="symbol">.</span>Contains<span class="symbol">(</span>p<span class="symbol">.</span>Name<span class="symbol">)</span><span class="symbol">)</span><span class="symbol">)</span>
<span class="symbol">{</span>
<span class="symbol">}</span>
</pre>
</figure>
<h2 id="retrieving-the-value-of-a-property">Retrieving the value of a property</h2>
<p>The <code>PropertyInfo</code> class has a <code>GetValue</code> method that can be
used to read the value of a property. Its most basic usage is to
pass in the instance object (or null if you want to read a
static property) and any index parameters (or null if no index
parameters are supported).</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">object</span> valueA<span class="symbol">;</span>
<span class="keyword">object</span> valueB<span class="symbol">;</span>

valueA <span class="symbol">=</span> propertyInfo<span class="symbol">.</span>GetValue<span class="symbol">(</span>objectA<span class="symbol">,</span> <span class="keyword">null</span><span class="symbol">)</span><span class="symbol">;</span>
valueB <span class="symbol">=</span> propertyInfo<span class="symbol">.</span>GetValue<span class="symbol">(</span>objectB<span class="symbol">,</span> <span class="keyword">null</span><span class="symbol">)</span><span class="symbol">;</span>
</pre>
</figure>
<p>The sample function described in this article doesn't currently
support indexed properties.</p>
<h2 id="determining-if-a-property-can-be-directly-compared">Determining if a property can be directly compared</h2>
<p>Some properties are simple types, such as an <code>int</code> or a <code>string</code>
and are very easy to compare. What happens if a property returns
some other object such as a collection of strings, or a complex
class?</p>
<p>In this case, I try and see if the type supports <code>IComparable</code>
by calling the <code>IsAssignableFrom</code> method. You need to call this
from the type you would like to create, passing in the source
type.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">return</span> <span class="keyword">typeof</span><span class="symbol">(</span>IComparable<span class="symbol">)</span><span class="symbol">.</span>IsAssignableFrom<span class="symbol">(</span>type<span class="symbol">)</span>
</pre>
</figure>
<p>I also check the <code>IsPrimitive</code> and <code>IsValueType</code> properties of
the source type, although this is possibly redundant as all the
base types I've checked so far all support <code>IComparable</code>.</p>
<h2 id="directly-comparing-values">Directly comparing values</h2>
<p>Assuming that I can directly compare a value, first I check if
one of the values is null - if one value is null and one false,
I immediately return a mismatch.</p>
<p>Otherwise, if <code>IComparable</code> is available, then I obtain an
instance of it from the first value and call its <code>CompareTo</code>
method, passing in the second value.</p>
<p>If <code>IComparable</code> is not supported, then I fallback to
<code>object.Equals</code>.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="keyword">bool</span> result<span class="symbol">;</span>
IComparable selfValueComparer<span class="symbol">;</span>

selfValueComparer <span class="symbol">=</span> valueA <span class="keyword">as</span> IComparable<span class="symbol">;</span>

<span class="keyword">if</span> <span class="symbol">(</span>valueA <span class="symbol">==</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> valueB <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">||</span> valueA <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> valueB <span class="symbol">==</span> <span class="keyword">null</span><span class="symbol">)</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span> <span class="comment">// one of the values is null</span>
<span class="keyword">else</span> <span class="keyword">if</span> <span class="symbol">(</span>selfValueComparer <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> selfValueComparer<span class="symbol">.</span>CompareTo<span class="symbol">(</span>valueB<span class="symbol">)</span> <span class="symbol">!=</span> <span class="number">0</span><span class="symbol">)</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span> <span class="comment">// the comparison using IComparable failed</span>
<span class="keyword">else</span> <span class="keyword">if</span> <span class="symbol">(</span><span class="symbol">!</span><span class="keyword">object</span><span class="symbol">.</span>Equals<span class="symbol">(</span>valueA<span class="symbol">,</span> valueB<span class="symbol">)</span><span class="symbol">)</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span> <span class="comment">// the comparison using Equals failed</span>
<span class="keyword">else</span>
 result <span class="symbol">=</span> <span class="keyword">true</span><span class="symbol">;</span> <span class="comment">// match</span>

<span class="keyword">return</span> result<span class="symbol">;</span>
</pre>
</figure>
<h2 id="comparing-objects">Comparing objects</h2>
<p>If the values could not be directly compared, and do not
implement <code>IEnumerable</code> (as described in the next section) then
I assume the properties are objects and call the compare objects
function again on the properties.</p>
<p>This works nicely, but has one critical flaw - if you have a
child object which has a property reference to a parent item,
then the function will get stuck in a recursive loop. Currently
the only workaround is to ensure that such parent properties are
excluded via the ignore list functionality of the compare
function.</p>
<h2 id="comparing-collections">Comparing collections</h2>
<p>If the direct compare check failed, but the property type
supports <code>IEnumerable</code>, then some Linq is used to obtain the
collection of items.</p>
<p>To save time, a count check is made and if the counts do not
match (or one of the collections is null and the other is not),
then an automatic mismatch is returned. If the counts do match,
then all items are compared in the same manner as the parent
objects.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
IEnumerable<span class="symbol">&lt;</span><span class="keyword">object</span><span class="symbol">&gt;</span> collectionItems<span class="number">1</span><span class="symbol">;</span>
IEnumerable<span class="symbol">&lt;</span><span class="keyword">object</span><span class="symbol">&gt;</span> collectionItems<span class="number">2</span><span class="symbol">;</span>
<span class="keyword">int</span> collectionItemsCount<span class="number">1</span><span class="symbol">;</span>
<span class="keyword">int</span> collectionItemsCount<span class="number">2</span><span class="symbol">;</span>

collectionItems<span class="number">1</span> <span class="symbol">=</span> <span class="symbol">(</span><span class="symbol">(</span>IEnumerable<span class="symbol">)</span>valueA<span class="symbol">)</span><span class="symbol">.</span>Cast<span class="symbol">&lt;</span><span class="keyword">object</span><span class="symbol">&gt;</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
collectionItems<span class="number">2</span> <span class="symbol">=</span> <span class="symbol">(</span><span class="symbol">(</span>IEnumerable<span class="symbol">)</span>valueB<span class="symbol">)</span><span class="symbol">.</span>Cast<span class="symbol">&lt;</span><span class="keyword">object</span><span class="symbol">&gt;</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
collectionItemsCount<span class="number">1</span> <span class="symbol">=</span> collectionItems<span class="number">1</span><span class="symbol">.</span>Count<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
collectionItemsCount<span class="number">2</span> <span class="symbol">=</span> collectionItems<span class="number">2</span><span class="symbol">.</span>Count<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
</pre>
</figure>
<p>I have tested this code on generic lists such as <code>List&lt;string&gt;</code>,
and on strongly typed collections which inherit from
<code>Collection&lt;TValue&gt;</code> with success.</p>
<h2 id="the-code">The code</h2>
<p>Below is the comparison code. Please note that it won't handle
all situations - as mentioned indexed properties aren't
supported. In addition, if you throw a complex object such as a
<code>DataReader</code> I suspect it will throw a fit on that. I also
haven't tested it on generic properties, it'll probably crash on
those too. But it has worked nicely for the original purpose I
wrote it for.</p>
<p>Also, as I was running this from a Console application, you may
wish to replace the calls to <code>Console.WriteLine</code> with either
<code>Debug.WriteLine</code> or even return them as an out parameter.</p>
<figure class="lang-csharp highlight"><figcaption><span>csharp</span></figcaption><pre class="code">
<span class="selector-tag">///</span> <span class="selector-tag">&lt;summary&gt;</span>
<span class="selector-tag">///</span><span class="comment"> Compares the properties of two objects of the same type and returns if all properties are equal.</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;/summary&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;param name=&quot;objectA&quot;&gt;</span><span class="comment">The first object to compare.&lt;/param&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;param name=&quot;objectB&quot;&gt;</span><span class="comment">The second object to compre.&lt;/param&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;param name=&quot;ignoreList&quot;&gt;</span><span class="comment">A list of property names to ignore from the comparison.&lt;/param&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;returns&gt;</span><span class="selector-tag">&lt;c&gt;</span><span class="comment">true&lt;/c&gt; if all property values are equal, otherwise &lt;c&gt;false&lt;/c&gt;.&lt;/returns&gt;</span>
<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">bool</span> AreObjectsEqual<span class="symbol">(</span><span class="keyword">object</span> objectA<span class="symbol">,</span> <span class="keyword">object</span> objectB<span class="symbol">,</span> <span class="keyword">params</span> <span class="keyword">string</span><span class="symbol">[</span><span class="symbol">]</span> ignoreList<span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">bool</span> result<span class="symbol">;</span>

 <span class="keyword">if</span> <span class="symbol">(</span>objectA <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> objectB <span class="symbol">!=</span> <span class="keyword">null</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 Type objectType<span class="symbol">;</span>

 objectType <span class="symbol">=</span> objectA<span class="symbol">.</span>GetType<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>

 result <span class="symbol">=</span> <span class="keyword">true</span><span class="symbol">;</span> <span class="comment">// assume by default they are equal</span>

 <span class="keyword">foreach</span> <span class="symbol">(</span>PropertyInfo propertyInfo <span class="keyword">in</span> objectType<span class="symbol">.</span>GetProperties<span class="symbol">(</span>BindingFlags<span class="symbol">.</span>Public <span class="symbol">|</span> BindingFlags<span class="symbol">.</span>Instance<span class="symbol">)</span><span class="symbol">.</span>Where<span class="symbol">(</span>p <span class="symbol">=&gt;</span> p<span class="symbol">.</span>CanRead <span class="symbol">&amp;&amp;</span> <span class="symbol">!</span>ignoreList<span class="symbol">.</span>Contains<span class="symbol">(</span>p<span class="symbol">.</span>Name<span class="symbol">)</span><span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">object</span> valueA<span class="symbol">;</span>
 <span class="keyword">object</span> valueB<span class="symbol">;</span>

 valueA <span class="symbol">=</span> propertyInfo<span class="symbol">.</span>GetValue<span class="symbol">(</span>objectA<span class="symbol">,</span> <span class="keyword">null</span><span class="symbol">)</span><span class="symbol">;</span>
 valueB <span class="symbol">=</span> propertyInfo<span class="symbol">.</span>GetValue<span class="symbol">(</span>objectB<span class="symbol">,</span> <span class="keyword">null</span><span class="symbol">)</span><span class="symbol">;</span>

 <span class="comment">// if it is a primitive type, value type or implements IComparable, just directly try and compare the value</span>
 <span class="keyword">if</span> <span class="symbol">(</span>CanDirectlyCompare<span class="symbol">(</span>propertyInfo<span class="symbol">.</span>PropertyType<span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">if</span> <span class="symbol">(</span><span class="symbol">!</span>AreValuesEqual<span class="symbol">(</span>valueA<span class="symbol">,</span> valueB<span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span><span class="string">&quot;Mismatch with property &#39;{0}.{1}&#39; found.&quot;</span><span class="symbol">,</span> objectType<span class="symbol">.</span>FullName<span class="symbol">,</span> propertyInfo<span class="symbol">.</span>Name<span class="symbol">)</span><span class="symbol">;</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="comment">// if it implements IEnumerable, then scan any items</span>
 <span class="keyword">else</span> <span class="keyword">if</span> <span class="symbol">(</span><span class="keyword">typeof</span><span class="symbol">(</span>IEnumerable<span class="symbol">)</span><span class="symbol">.</span>IsAssignableFrom<span class="symbol">(</span>propertyInfo<span class="symbol">.</span>PropertyType<span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 IEnumerable<span class="symbol">&lt;</span><span class="keyword">object</span><span class="symbol">&gt;</span> collectionItems<span class="number">1</span><span class="symbol">;</span>
 IEnumerable<span class="symbol">&lt;</span><span class="keyword">object</span><span class="symbol">&gt;</span> collectionItems<span class="number">2</span><span class="symbol">;</span>
 <span class="keyword">int</span> collectionItemsCount<span class="number">1</span><span class="symbol">;</span>
 <span class="keyword">int</span> collectionItemsCount<span class="number">2</span><span class="symbol">;</span>

 <span class="comment">// null check</span>
 <span class="keyword">if</span> <span class="symbol">(</span>valueA <span class="symbol">==</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> valueB <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">||</span> valueA <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> valueB <span class="symbol">==</span> <span class="keyword">null</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span><span class="string">&quot;Mismatch with property &#39;{0}.{1}&#39; found.&quot;</span><span class="symbol">,</span> objectType<span class="symbol">.</span>FullName<span class="symbol">,</span> propertyInfo<span class="symbol">.</span>Name<span class="symbol">)</span><span class="symbol">;</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="keyword">else</span> <span class="keyword">if</span> <span class="symbol">(</span>valueA <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> valueB <span class="symbol">!=</span> <span class="keyword">null</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 collectionItems<span class="number">1</span> <span class="symbol">=</span> <span class="symbol">(</span><span class="symbol">(</span>IEnumerable<span class="symbol">)</span>valueA<span class="symbol">)</span><span class="symbol">.</span>Cast<span class="symbol">&lt;</span><span class="keyword">object</span><span class="symbol">&gt;</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
 collectionItems<span class="number">2</span> <span class="symbol">=</span> <span class="symbol">(</span><span class="symbol">(</span>IEnumerable<span class="symbol">)</span>valueB<span class="symbol">)</span><span class="symbol">.</span>Cast<span class="symbol">&lt;</span><span class="keyword">object</span><span class="symbol">&gt;</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
 collectionItemsCount<span class="number">1</span> <span class="symbol">=</span> collectionItems<span class="number">1</span><span class="symbol">.</span>Count<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>
 collectionItemsCount<span class="number">2</span> <span class="symbol">=</span> collectionItems<span class="number">2</span><span class="symbol">.</span>Count<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>

 <span class="comment">// check the counts to ensure they match</span>
 <span class="keyword">if</span> <span class="symbol">(</span>collectionItemsCount<span class="number">1</span> <span class="symbol">!=</span> collectionItemsCount<span class="number">2</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span><span class="string">&quot;Collection counts for property &#39;{0}.{1}&#39; do not match.&quot;</span><span class="symbol">,</span> objectType<span class="symbol">.</span>FullName<span class="symbol">,</span> propertyInfo<span class="symbol">.</span>Name<span class="symbol">)</span><span class="symbol">;</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="comment">// and if they do, compare each item... this assumes both collections have the same order</span>
 <span class="keyword">else</span>
 <span class="symbol">{</span>
 <span class="keyword">for</span> <span class="symbol">(</span><span class="keyword">int</span> i <span class="symbol">=</span> <span class="number">0</span><span class="symbol">;</span> i <span class="symbol">&lt;</span> collectionItemsCount<span class="number">1</span><span class="symbol">;</span> i<span class="symbol">++</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">object</span> collectionItem<span class="number">1</span><span class="symbol">;</span>
 <span class="keyword">object</span> collectionItem<span class="number">2</span><span class="symbol">;</span>
 Type collectionItemType<span class="symbol">;</span>

 collectionItem<span class="number">1</span> <span class="symbol">=</span> collectionItems<span class="number">1</span><span class="symbol">.</span>ElementAt<span class="symbol">(</span>i<span class="symbol">)</span><span class="symbol">;</span>
 collectionItem<span class="number">2</span> <span class="symbol">=</span> collectionItems<span class="number">2</span><span class="symbol">.</span>ElementAt<span class="symbol">(</span>i<span class="symbol">)</span><span class="symbol">;</span>
 collectionItemType <span class="symbol">=</span> collectionItem<span class="number">1</span><span class="symbol">.</span>GetType<span class="symbol">(</span><span class="symbol">)</span><span class="symbol">;</span>

 <span class="keyword">if</span> <span class="symbol">(</span>CanDirectlyCompare<span class="symbol">(</span>collectionItemType<span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">if</span> <span class="symbol">(</span><span class="symbol">!</span>AreValuesEqual<span class="symbol">(</span>collectionItem<span class="number">1</span><span class="symbol">,</span> collectionItem<span class="number">2</span><span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span><span class="string">&quot;Item {0} in property collection &#39;{1}.{2}&#39; does not match.&quot;</span><span class="symbol">,</span> i<span class="symbol">,</span> objectType<span class="symbol">.</span>FullName<span class="symbol">,</span> propertyInfo<span class="symbol">.</span>Name<span class="symbol">)</span><span class="symbol">;</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="keyword">else</span> <span class="keyword">if</span> <span class="symbol">(</span><span class="symbol">!</span>AreObjectsEqual<span class="symbol">(</span>collectionItem<span class="number">1</span><span class="symbol">,</span> collectionItem<span class="number">2</span><span class="symbol">,</span> ignoreList<span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span><span class="string">&quot;Item {0} in property collection &#39;{1}.{2}&#39; does not match.&quot;</span><span class="symbol">,</span> i<span class="symbol">,</span> objectType<span class="symbol">.</span>FullName<span class="symbol">,</span> propertyInfo<span class="symbol">.</span>Name<span class="symbol">)</span><span class="symbol">;</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="keyword">else</span> <span class="keyword">if</span> <span class="symbol">(</span>propertyInfo<span class="symbol">.</span>PropertyType<span class="symbol">.</span>IsClass<span class="symbol">)</span>
 <span class="symbol">{</span>
 <span class="keyword">if</span> <span class="symbol">(</span><span class="symbol">!</span>AreObjectsEqual<span class="symbol">(</span>propertyInfo<span class="symbol">.</span>GetValue<span class="symbol">(</span>objectA<span class="symbol">,</span> <span class="keyword">null</span><span class="symbol">)</span><span class="symbol">,</span> propertyInfo<span class="symbol">.</span>GetValue<span class="symbol">(</span>objectB<span class="symbol">,</span> <span class="keyword">null</span><span class="symbol">)</span><span class="symbol">,</span> ignoreList<span class="symbol">)</span><span class="symbol">)</span>
 <span class="symbol">{</span>
 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span><span class="string">&quot;Mismatch with property &#39;{0}.{1}&#39; found.&quot;</span><span class="symbol">,</span> objectType<span class="symbol">.</span>FullName<span class="symbol">,</span> propertyInfo<span class="symbol">.</span>Name<span class="symbol">)</span><span class="symbol">;</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="keyword">else</span>
 <span class="symbol">{</span>
 Console<span class="symbol">.</span>WriteLine<span class="symbol">(</span><span class="string">&quot;Cannot compare property &#39;{0}.{1}&#39;.&quot;</span><span class="symbol">,</span> objectType<span class="symbol">.</span>FullName<span class="symbol">,</span> propertyInfo<span class="symbol">.</span>Name<span class="symbol">)</span><span class="symbol">;</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="symbol">}</span>
 <span class="keyword">else</span>
 result <span class="symbol">=</span> <span class="keyword">object</span><span class="symbol">.</span>Equals<span class="symbol">(</span>objectA<span class="symbol">,</span> objectB<span class="symbol">)</span><span class="symbol">;</span>

 <span class="keyword">return</span> result<span class="symbol">;</span>
<span class="symbol">}</span>

<span class="selector-tag">///</span> <span class="selector-tag">&lt;summary&gt;</span>
<span class="selector-tag">///</span><span class="comment"> Determines whether value instances of the specified type can be directly compared.</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;/summary&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;param name=&quot;type&quot;&gt;</span><span class="comment">The type.&lt;/param&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;returns&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;c&gt;</span><span class="comment">true&lt;/c&gt; if this value instances of the specified type can be directly compared; otherwise, &lt;c&gt;false&lt;/c&gt;.</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;/returns&gt;</span>
<span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">bool</span> CanDirectlyCompare<span class="symbol">(</span>Type type<span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">return</span> <span class="keyword">typeof</span><span class="symbol">(</span>IComparable<span class="symbol">)</span><span class="symbol">.</span>IsAssignableFrom<span class="symbol">(</span>type<span class="symbol">)</span> <span class="symbol">||</span> type<span class="symbol">.</span>IsPrimitive <span class="symbol">||</span> type<span class="symbol">.</span>IsValueType<span class="symbol">;</span>
<span class="symbol">}</span>

<span class="selector-tag">///</span> <span class="selector-tag">&lt;summary&gt;</span>
<span class="selector-tag">///</span><span class="comment"> Compares two values and returns if they are the same.</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;/summary&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;param name=&quot;valueA&quot;&gt;</span><span class="comment">The first value to compare.&lt;/param&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;param name=&quot;valueB&quot;&gt;</span><span class="comment">The second value to compare.&lt;/param&gt;</span>
<span class="selector-tag">///</span> <span class="selector-tag">&lt;returns&gt;</span><span class="selector-tag">&lt;c&gt;</span><span class="comment">true&lt;/c&gt; if both values match, otherwise &lt;c&gt;false&lt;/c&gt;.&lt;/returns&gt;</span>
<span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">bool</span> AreValuesEqual<span class="symbol">(</span><span class="keyword">object</span> valueA<span class="symbol">,</span> <span class="keyword">object</span> valueB<span class="symbol">)</span>
<span class="symbol">{</span>
 <span class="keyword">bool</span> result<span class="symbol">;</span>
 IComparable selfValueComparer<span class="symbol">;</span>

 selfValueComparer <span class="symbol">=</span> valueA <span class="keyword">as</span> IComparable<span class="symbol">;</span>

 <span class="keyword">if</span> <span class="symbol">(</span>valueA <span class="symbol">==</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> valueB <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">||</span> valueA <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> valueB <span class="symbol">==</span> <span class="keyword">null</span><span class="symbol">)</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span> <span class="comment">// one of the values is null</span>
 <span class="keyword">else</span> <span class="keyword">if</span> <span class="symbol">(</span>selfValueComparer <span class="symbol">!=</span> <span class="keyword">null</span> <span class="symbol">&amp;&amp;</span> selfValueComparer<span class="symbol">.</span>CompareTo<span class="symbol">(</span>valueB<span class="symbol">)</span> <span class="symbol">!=</span> <span class="number">0</span><span class="symbol">)</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span> <span class="comment">// the comparison using IComparable failed</span>
 <span class="keyword">else</span> <span class="keyword">if</span> <span class="symbol">(</span><span class="symbol">!</span><span class="keyword">object</span><span class="symbol">.</span>Equals<span class="symbol">(</span>valueA<span class="symbol">,</span> valueB<span class="symbol">)</span><span class="symbol">)</span>
 result <span class="symbol">=</span> <span class="keyword">false</span><span class="symbol">;</span> <span class="comment">// the comparison using Equals failed</span>
 <span class="keyword">else</span>
 result <span class="symbol">=</span> <span class="keyword">true</span><span class="symbol">;</span> <span class="comment">// match</span>

 <span class="keyword">return</span> result<span class="symbol">;</span>
<span class="symbol">}</span>
</pre>
</figure>
<p>I hope you find these helper methods useful, this article will
be updated if and when the methods are expanded with new
functionality.</p>
<h2 id="update-history">Update History</h2>
<ul>
<li>2010-11-05 - First published</li>
<li>2020-11-21 - Updated formatting</li>
</ul>

<p><small>
All content <a href="https://devblog.cyotek.com/copyright-and-trademarks">Copyright (c) by Cyotek Ltd</a> or its respective writers. Permission to reproduce news and web log entries and other RSS feed content in unmodified form without notice is granted provided they are not used to endorse or promote any products or opinions (other than what was expressed by the author) and without taking them out of context. Written permission from the copyright owner must be obtained for everything else.<br />Original URL of this content is https://devblog.cyotek.com/post/comparing-the-properties-of-two-objects-via-reflection .
</small></p>Richard Mosshttps://www.cyotek.com/richard.moss@cyotek.com