Sunday, July 31, 2011

How "dynamic" made my life easier


Some coworker said once "Every time you hear dynamic means a load of troubles is coming by". I didn't agree. I know lots of interesting stuff can only be done using Reflection and even Reflection.Emit. Just to give some context, you are talking about Microsoft Framework 4.0 and the new type dynamic type declaration.

As you know C# is a statically typed language. As you also know, this means you must declare the type of every variable, field or property, before you can use it. The var keyword didn't change that rule a bit. Using var you are implicitly declaring tha variable type. The compiler knows the correct type of  var and the keyword is replaced by the correct type at compile time.

Let's rephrase: the type of each variable, field or property must be known at compile time. Then Framework 4.0 and _Dynamic Language Runtime_ brought us dynamic. We must change the definition above as the real type dynamic is unknown at compile time. A dynamic type can be any type at all so it's legal to do any operation you like with it. The compiler won't complain about it being incorrect as it doesn't know the real type.

You can argue that System.Object could do the the trick but you also know the range of operations you can do with System.Object is very narrow and you have to cast it to another type in order to get the same kind of usability, I mean in order to support all operations other types support. No more limitations like that:
  • declare a variable as dynamic
  • your first assignmenet to this variable defines the real type it will have
  • the legal or illegal operations will be evaluated after this assignement
What's the catch? Incompatibilities that couldn't show on compile time will show at runtime. So if you practice "jerk programming", you will get "a load of troubles" and my coworker's statement will prove correct.

What do I need dynamic for?
The classical problem is the "custom properties" issue. You have an business application but every customer wants its own set of extra properties and the requirements of the customer can overcome your worst scenarios/nighmares. You could go the Reflection.Emit way but that's really hard for most programers. Let's try the dynamic way.

Define you CustomPropery class like this:

using System;

public class CustomProperty
{
    #region Private Fields

    private string _name = String.Empty;
    private string _type = String.Empty;
    private dynamic _value;

    #endregion

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    public string Type
    {
        get { return _type; }
        set { _type = value; }
    }

    public dynamic Value
    {
        get { return _value; }
        set { _value = value; }
    }
}


Notice dynamic is used both on the field and on the property.
I suppose you will now read the CustomProperty definitions from some storage be it a database, XML file, it really does't matter.

Now you need a method that converts the type that you read as a String into a Type.

private static Type GetDataType(string type)
{
    Type propType = Type.GetType(type);
    if (propType == null)
        propType = Type.GetType("System." + type);
    if (propType == null)
        propType = Type.GetType("App.CustomProperties." + type);

    return propType;
}


Just to put it all together, after reading the definitions to a prop of PropertyInfo type, you assign the real type like this:

var customProperty = new CustomProperty();
customProperty.Name = prop.Name;
customProperty.Type = prop.PropertyType.Name;

Type targetType = GetDataType(customProperty.Type);
if (targetType != null)
{
    if (targetType.IsEnum)
        customProperty.Value = ConvertStringToEnum(targetType, "");
    else if (targetType == typeof (Int16))
        customProperty.Value = (Int16) 0;
    else if (targetType == typeof (Int32))
        customProperty.Value = (Int32) 0;
    else if (targetType == typeof (Int64))
        customProperty.Value = (Int64) 0;
}
else
{
    customProperty.Value = " ";
    customProperty.Value = string.Empty;
}


After the first assignement juts to define the real Type,  you can now take care of assigning the real value, knowing it will have the correct Type.

In this example I need the properties for use in a PropertyGrid. In each grid row, I show the customProperty.Name followed by the customProperty.Value. The sample presented here is very limited in scope and isn't really a How To. The point is:
  1. there is no keyword to define the real type of a dynamic variable/field/property
  2. the real type is defined by the first assignement
  3. do this assignment as soon as you know the real type
  4. assign the actual value after the previous assignment

No comments:

Post a Comment