Standing on the shoulders of giants. RSS 2.0
Page 1 of 1 in the VisualStudio2010 category
# Saturday, May 30, 2009

The new dynamic keyword and the DLR in C# 4 and the .NET Framework 4.0 can be used for good, as displayed by IronRuby, IronPython and several other samples.

But it’s much more to fun to use it for evil… by making Reflection simple.

In C# 3.0 invoking members through reflection, was kind of odd and certainly not very readable.

var employee = new Employee();
var members = employee.GetType().GetMember("age", MemberTypes.All,
                BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

((FieldInfo)members[0]).SetValue(employee, 30);

By wrapping all reflection magic in a dynamic object the same call would look like:

var employee = (new Employee()).AsDynamic();

employee.Name = "Paul van Brenk";
employee.Age = 30;

Console.WriteLine("Employee {0} is {1} years old.", employee.Name, employee.Age);

How this works is relatively easy.. by deriving a wrapper class from the new DynamicObject and overriding the TrySetMember and TryGetMember object to do the dirty work for you.

static class DynamicHelper
{
    public static dynamic AsDynamic(this T source)
    {
        return new DynamicReflection(source);
    }

    class DynamicReflection : DynamicObject
    {
        public DynamicReflection(T source)
            : base()
        {
            this.Source = source;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            // find the member
            MemberInfo member;
            if (!TryFindMember(binder.Name, out member))
            {
                return false;
            }

            // we can only set values to fields and properties
            // using reflection
            switch (member.MemberType)
            {
                /* todo: check the type of the incoming value and the type of 
                  the property. */
                case (MemberTypes.Field):
                    ((FieldInfo)member).SetValue(Source, value);
                    return true;
                case (MemberTypes.Property):
                    ((PropertyInfo)member).SetValue(Source, value,/*ndex*/ null); // we don't support indexed properties
                    return true;
            }

            // didn't work
            return false;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            // find the member
            MemberInfo member;
            if (!TryFindMember(binder.Name, out member))
            {
                result = null;
                return false;
            }

            // we can only set values to fields and properties
            // using reflection
            switch (member.MemberType)
            {
                /* todo: check the type of the incoming value and the type of 
                  the property. */
                case (MemberTypes.Field):
                    result = ((FieldInfo)member).GetValue(Source);
                    return true;
                case (MemberTypes.Property):
                    result = ((PropertyInfo)member).GetValue(Source,/*ndex*/ null); // we don't support indexed properties
                    return true;
            }

            // didn't work
            result = null;
            return false;
        }

        private bool TryFindMember(string name, out MemberInfo memberInfo)
        {
            // find the member
            var members = Type.GetMember(name, MemberTypes.All,
                                      BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            // more than 1 not supported for now
            if (members.Length != 1) { memberInfo = null; return false; }

            memberInfo = members[0];
            return true;
        }

        private Type Type { get { return typeof(T); } }

        public T Source { get; private set; }
    }
}

More info about implementing dynamic objects and behavior can be found on the DLR CodePlex site (esp. Getting Started with the DLR as a Library Author).

Source: Program.cs.txt

Saturday, May 30, 2009 7:53:08 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
C# | Visual Studio 2010
Ads
About
© Copyright 2010
Paul van Brenk
Sign In
newtelligence dasBlog 2.3.9074.18820
All Content © 2010, Paul van Brenk
DasBlog theme 'Business' created by Christoph De Baene (delarou)