Tuesday 31 March 2009

System.Reflection To the Rescue

Many people ask if there is a possibility to call a method, if we have its name as string. Actually, it is very useful feature. Imagine we have an Object with several properties which represent the same thing, but in different languages.

class MyClass
{
    public string State_EN;
    public string State_DE;
    public string State_RU;
}

We want to show the state of MyClass object in proper language. We create a method for that

public string State(string language)
{
}

Language is the 2-letter code representation of language ("EN", "DE", "RU"...). So what should be inside the State method? Solutions with "if" and "switch" are not good - if you have to add more languages, you must rewrite the State method. But we are lazy and don't want to do that. What we need here is System.Reflection.

using System.Reflection;
[...]
public string State(string language)
{
    PropertyInfo property = typeof(MyClass).GetProperty("State_" + language);//find the property
    if (property != null)
        return (string)property.GetValue(this, null);//get value of the property
    return null;
}

The same way we can search for method, if we know the method's name (with GetMethod instead of GetProperty). And call it with "Invoke" and proper parameters.

Wednesday 18 March 2009

Using Generics With System.Nullable<T>

When we have a Nullable type value and we want to assign it to some control, then we need to check if is not null first.

SomeLabel.Text = object.MyProperty.HasValue ? object.MyProperty.Value : String.Empty;

But if we have many nullable properties? I don't want to copy/paste this check on every line. So we need a method, that checks for nulls. But I also don't want several methods for every type. So we need to use generics.

I created some methods for myself

public static string ValueOrEmptyString<T>(Nullable<T> obj) where T : struct
{
  return obj.HasValue ? obj.Value.ToString() : "";
}

public static T ValueOrDefault<T>(Nullable<T> obj, T defaultValue) where T : struct
{
  return obj.HasValue ? obj.Value : defaultValue;
}

public static T ValueOrDefault<T>(Nullable<T> obj) where T : struct
{
  return obj.HasValue ? obj.Value : default(T);
}

"where T : struct" - is needed for compiler to understand that this method is allowed only for types that belong to System.ValueType.

I can use these methods like that

SomeLabel.Text = ValueOrEmptyString<int>( object.MyIntProperty );
SomeDateTimeControl.Date = ValueOrDefault<DateTime>( object.MyDateTimeProperty );
SomeReferenceControl.SelectedObjecId = ValueOrDefault<int>( object.MyIntProperty, -1 );