Case-insentive datamapper

Case-insentive datamapper

Old forum URL: forums.lhotka.net/forums/t/2585.aspx


kobruleht posted on Sunday, March 25, 2007

I use modified Rockford Lhotka excellent SetPropertyValue()
from DataMapper class to load objects from database.
My entity object property names are mixed case.
DataReader returns lower-case only column names.
So SetPropertyValue() cannot map columns to property names.

How to change this code so that it does not depend on the propertyName case ?

<pre>
/// <summary>
/// Sets an object's property with the specified value,
/// coercing that value to the appropriate type if possible.
/// </summary>
/// <param name="target">Object containing the property to set.</param>
/// <param name="propertyName">Name of the property to set.</param>
/// <param name="value">Value to set into the property.</param>
public static void SetPropertyValue(
   object target, string propertyName, object value)
 {
   PropertyInfo propertyInfo =
        target.GetType().GetProperty(propertyName);
   if (value == null)
        propertyInfo.SetValue(target, value, null);
   else
      {
        Type pType =
          Utilities.GetPropertyType(propertyInfo.PropertyType);
        Type vType =
          Utilities.GetPropertyType(value.GetType());
        if (pType.Equals(vType))
        {
          // types match, just copy value
          propertyInfo.SetValue(target, value, null);
        }
        else
        {
          // types don't match, try to coerce
          if (pType.Equals(typeof(Guid)))
            propertyInfo.SetValue(
              target, new Guid(value.ToString()), null);
          else if (pType.IsEnum && vType.Equals(typeof(string)))
            propertyInfo.SetValue(target, Enum.Parse(pType, value.ToString()), null);
     else if (pType.IsEnum && vType.Equals(typeof(decimal)))
      propertyInfo.SetValue(target,
       Enum.Parse(pType, value.ToString()), null);

     else
            propertyInfo.SetValue(
              target, Convert.ChangeType(value, pType), null);
        }
      }
    }
  }
}
</pre>

Bayu replied on Monday, March 26, 2007

Hi!

Make use of TypeDescriptor (available from System.ComponentModel namespace):

        Dim pDescriptors As PropertyDescriptorCollection = TypeDescriptor.GetProperties(objectType)
        Dim pDescriptor As PropertyDescriptor = pDescriptors.Find(propertyName, True)

(It's VB code)

- the first line will give you a searchable (!) collection.
- the second line invokes Find on this collection where the second argument sets ignoreCase to True

You can then retrieve the name of the property in correct casing from the found descriptor:

        Dim pName As String = pDescriptor.Name

This name can then be fed to your call that returns the PropertyInfo object:

        Dim pInfo As PropertyInfo = target.GetType().GetProperty(pName)

And you should be good to go!

Bayu

kobruleht replied on Monday, March 26, 2007

How about simply using:

   PropertyInfo propertyInfo =
       target.GetType().GetProperty(propertyName, System.Reflection.BindingFlags.Instance |
                        System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Public)

This is simpler than you approach.

Can Racky add this change to this method ?

Bayu replied on Wednesday, March 28, 2007

Ah,

Good one! Much cleaner than what I proposed.

Bayu

ajj3085 replied on Wednesday, March 28, 2007

The only problem with that change is if you actually have two properties which differ by casing only.  While I agree it shouldn't be done and is not CLS compliant, if someone where to do that, they'd have mysterious bugs in their code.

Bayu replied on Thursday, March 29, 2007

ajj3085:
The only problem with that change is if you actually have two properties which differ by casing only.  While I agree it shouldn't be done and is not CLS compliant, if someone where to do that, they'd have mysterious bugs in their code.


Thankfully that is impossible in VB.

Really is an ugly remnant from C(++) and co imo.

;-)

Bayu

ajj3085 replied on Thursday, March 29, 2007

Personally, I like the case sensitivity.  I use this to seperate fields from properties..

public string MyString { get { return myString; } set { myString = value; }
private string myString;

I dislike using the _ or  having to change the name of the field because a language is case insensitive.

Obviously, my opinion.  Smile [:)]

Skafa replied on Thursday, March 29, 2007

I dó like using te 'm' or '_' prefix for private fields. For readability (you can quickly see private fields in your code), to avoid mistakes (I use VB ánd C#), but far most because you get a nice fast accessable list in IntelliSense when beginnen typing :-)

ajj3085 replied on Thursday, March 29, 2007

Everybody has their own style.  What is the 'm' supposed to mean though?  We used to use s for string, i for integer, etc., but that was in the classic asp days.  We used m for module level variables... but that doesn't make sense to me anymore because we don't have modules, we have classes, namespaces and assemblies.

Skafa replied on Thursday, March 29, 2007

I don't know for sure, but you see it in a lot of VB code. It could be something like member or something.

Bayu replied on Thursday, March 29, 2007

ajj3085:
What is the 'm' supposed to mean though?


I think there can only be one correct answer to this .........
It stands for MMMMMMMMMMMMMicrosoft of course!........ what'd ya think? ;-p

It's the 'M' of Making Money and for doing things Mightily diffferently, namely the MMMMicrosoft way!

;-)



No, I always thought it was for 'my', as in a a possessive noun that refers to the class. So it was supposed to be used for class-level (i.e. private) variables. You know, there were those days suddenly everything became 'mine' (as if it was Microsoft's before), think of the introduction of My Computer, My Documents, My Videos, My .. My, My .... (say this several times and you start to sound like those pelicans from Finding Nemo ;-) ).

Bayu


Copyright (c) Marimer LLC