/// <summary>
        /// This is the most generic method for getting a member's value.
        /// It will attempt to resolve the member by name and the get its value by invoking the
        /// callsite's delegate
        /// </summary>
        public T GetMember <T> (object o)
        {
            Stats.Increment(StatsCounter.GetMemberBinderInvoked);

            TypeLogger.LogType(o);

            // get accessor for value type T
            var accessor = o as IDynamicAccessor <T>;

            if (accessor != null)
            {
                return(accessor.GetMember(mName, ref mNameHint));
            }

            // fallback on object accessor and cast it to T
            var untypedAccessor = o as IDynamicAccessorUntyped;

            if (untypedAccessor != null)
            {
                // value can be null, undefined, or of type T
                object value = untypedAccessor.GetMember(mName, ref mNameHint);
                // convert value to T
                if (value == null)
                {
                    return(default(T));
                }
                else if (value is T)
                {
                    return((T)value);
                }
                else if (Dynamic.IsUndefined(value))
                {
                    return(Dynamic.GetUndefinedValue <T>());
                }
                else
                {
                    return(PlayScript.Dynamic.ConvertValue <T>(value));
                }
            }

            // resolve as dictionary (this is usually an expando)
            var dict = o as IDictionary <string, object>;

            if (dict != null)
            {
                Stats.Increment(StatsCounter.GetMemberBinder_Expando);

                // special case this for expando objects
                object value;
                if (dict.TryGetValue(mName, out value))
                {
                    // fast path empty cast just in case
                    if (value is T)
                    {
                        return((T)value);
                    }
                    else
                    {
                        return(PlayScript.Dynamic.ConvertValue <T>(value));
                    }
                }

                // key not found
                return(Dynamic.GetUndefinedValue <T>());
            }

            if (PlayScript.Dynamic.IsNullOrUndefined(o))
            {
                return(Dynamic.GetUndefinedValue <T>());
            }

            // determine if this is a instance member or a static member
            bool isStatic;
            Type otype;

            if (o is System.Type)
            {
                // static member
                otype    = (System.Type)o;
                o        = null;
                isStatic = true;
            }
            else
            {
                // instance member
                otype    = o.GetType();
                isStatic = false;
            }

            if (otype == mType)
            {
                // use cached resolve
                if (mProperty != null)
                {
                    Func <T> func;
                    if (o == mPreviousTarget)
                    {
                        func = (Func <T>)mPreviousFunc;
                    }
                    else
                    {
                        mPreviousFunc   = func = ActionCreator.CreatePropertyGetAction <T>(o, mProperty);
                        mPreviousTarget = o;
                    }
                    return(func());
                }

                if (mField != null)
                {
                    return(PlayScript.Dynamic.ConvertValue <T>(mField.GetValue(o)));
                }

                if (mMethod != null)
                {
                    // construct method delegate
                    return(PlayScript.Dynamic.ConvertValue <T>(Delegate.CreateDelegate(mTargetType, o, mMethod)));
                }

                // resolve as dynamic class
                var dc = o as IDynamicClass;
                if (dc != null)
                {
                    object result = dc.__GetDynamicValue(mName);
                    return(PlayScript.Dynamic.ConvertValue <T>(result));
                }

                if (mName == "constructor")
                {
                    return(PlayScript.Dynamic.ConvertValue <T> (otype));
                }

                throw new System.InvalidOperationException("Unhandled member type in PSGetMemberBinder");
            }

            // resolve name
            Stats.Increment(StatsCounter.GetMemberBinder_Resolve_Invoked);
            Stats.Start(StatsCounter.GetMemberBinder_Resolve_Time);

            // The constructor is a special synthetic property - we have to handle this for AS compatibility
            if (mName == "constructor")
            {
                // setup binding to field
                mType           = otype;
                mPreviousFunc   = null;
                mPreviousTarget = null;
                mProperty       = null;
                mField          = null;
                mMethod         = null;
                mTargetType     = typeof(Type);
                Stats.Stop(StatsCounter.GetMemberBinder_Resolve_Time);
                return(PlayScript.Dynamic.ConvertValue <T> (otype));
            }

            // resolve as property
            // TODO: we allow access to non-public properties for simplicity,
            // should cleanup to check access levels
            var property = otype.GetProperty(mName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

            if (property != null)
            {
                // found property
                var getter = property.GetGetMethod();
                if (getter != null && getter.IsStatic == isStatic)
                {
                    // setup binding to property
                    mType           = otype;
                    mPreviousFunc   = null;
                    mPreviousTarget = null;
                    mProperty       = property;
                    mPropertyGetter = property.GetGetMethod();
                    mField          = null;
                    mMethod         = null;
                    mTargetType     = property.PropertyType;
                    Stats.Stop(StatsCounter.GetMemberBinder_Resolve_Time);
                    return(PlayScript.Dynamic.ConvertValue <T>(mPropertyGetter.Invoke(o, null)));
                }
            }

            // resolve as field
            // TODO: we allow access to non-public fields for simplicity,
            // should cleanup to check access levels
            var field = otype.GetField(mName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

            if (field != null)
            {
                // found field
                if (field.IsStatic == isStatic)
                {
                    // setup binding to field
                    mType           = otype;
                    mPreviousFunc   = null;
                    mPreviousTarget = null;
                    mProperty       = null;
                    mField          = field;
                    mMethod         = null;
                    mTargetType     = field.FieldType;
                    Stats.Stop(StatsCounter.GetMemberBinder_Resolve_Time);
                    return(PlayScript.Dynamic.ConvertValue <T>(field.GetValue(o)));
                }
            }

            // resolve as method
            BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public;

            if (isStatic)
            {
                flags |= BindingFlags.Static;
            }
            else
            {
                flags |= BindingFlags.Instance;
            }
            var method = otype.GetMethod(mName, flags);

            if (method != null)
            {
                // setup binding to method
                mType           = otype;
                mPreviousFunc   = null;
                mPreviousTarget = null;
                mProperty       = null;
                mField          = null;
                mMethod         = method;
                mTargetType     = PlayScript.Dynamic.GetDelegateTypeForMethod(mMethod);
                Stats.Stop(StatsCounter.GetMemberBinder_Resolve_Time);
                return(PlayScript.Dynamic.ConvertValue <T>(Delegate.CreateDelegate(mTargetType, o, mMethod)));
            }

            if (o is IDynamicClass)
            {
                // dynamic class
                mType           = otype;
                mPreviousFunc   = null;
                mPreviousTarget = null;
                mProperty       = null;
                mField          = null;
                mMethod         = null;
                object result = ((IDynamicClass)o).__GetDynamicValue(mName);
                Stats.Stop(StatsCounter.GetMemberBinder_Resolve_Time);
                return(PlayScript.Dynamic.ConvertValue <T>(result));
            }

            Stats.Stop(StatsCounter.GetMemberBinder_Resolve_Time);

            return(Dynamic.GetUndefinedValue <T>());
        }
        /// <summary>
        /// This is the most generic method for getting a member's value.
        /// It will attempt to resolve the member by name and the get its value by invoking the
        /// callsite's delegate
        /// </summary>
        private static T GetMember <T> (CallSite site, object o)
        {
#if BINDERS_RUNTIME_STATS
            Stats.Increment(StatsCounter.GetMemberBinderInvoked);
#endif

            if (o == null)
            {
                return(default(T));
            }

            var binder = (PSGetMemberBinder)site.Binder;

            // resolve as dictionary
            var dict = o as IDictionary <string, object>;
            if (dict != null)
            {
                // special case this for expando objects
                object value;
                if (dict.TryGetValue(binder.name, out value))
                {
                    return(PlayScript.Dynamic.ConvertValue <T>(value));
                }

                // fall through if key not found
            }


            // determine if this is a instance member or a static member
            bool isStatic;
            Type otype;
            if (o is System.Type)
            {
                // static member
                otype    = (System.Type)o;
                o        = null;
                isStatic = true;
            }
            else
            {
                // instance member
                otype    = o.GetType();
                isStatic = false;
            }

            if (otype == binder.type)
            {
                // use cached resolve
                if (binder.property != null)
                {
                    Func <T> func;
                    if (o == binder.previousTarget)
                    {
                        func = (Func <T>)binder.previousFunc;
                    }
                    else
                    {
                        binder.previousFunc   = func = ActionCreator.CreatePropertyGetAction <T>(o, binder.property);
                        binder.previousTarget = o;
                    }
                    return(func());
                }

                if (binder.field != null)
                {
                    return(PlayScript.Dynamic.ConvertValue <T>(binder.field.GetValue(o)));
                }

                if (binder.method != null)
                {
                    // construct method delegate
                    return(PlayScript.Dynamic.ConvertValue <T>(Delegate.CreateDelegate(PlayScript.Dynamic.GetDelegateTypeForMethod(binder.method), o, binder.method)));
                }

                // resolve as dynamic class
                var dc = o as IDynamicClass;
                if (dc != null)
                {
                    object result = dc.__GetDynamicValue(binder.name);
                    return(PlayScript.Dynamic.ConvertValue <T>(result));
                }

                throw new System.InvalidOperationException("Unhandled member type in PSGetMemberBinder");
            }

            // resolve name

#if BINDERS_RUNTIME_STATS
            Stats.Increment(StatsCounter.GetMemberBinder_Resolve_Invoked);
#endif

            // resolve as property
            var property = otype.GetProperty(binder.name);
            if (property != null)
            {
                // found property
                var getter = property.GetGetMethod();
                if (getter != null && getter.IsPublic && getter.IsStatic == isStatic)
                {
                    // setup binding to property
                    binder.type     = otype;
                    binder.property = property;
                    binder.field    = null;
                    binder.method   = null;
                    return(PlayScript.Dynamic.ConvertValue <T>(property.GetValue(o, null)));
                }
            }

            // resolve as field
            var field = otype.GetField(binder.name);
            if (field != null)
            {
                // found field
                if (field.IsPublic && field.IsStatic == isStatic)
                {
                    // setup binding to field
                    binder.type     = otype;
                    binder.property = null;
                    binder.field    = field;
                    binder.method   = null;
                    return(PlayScript.Dynamic.ConvertValue <T>(field.GetValue(o)));
                }
            }

            // resolve as method
            BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public;
            if (isStatic)
            {
                flags |= BindingFlags.Static;
            }
            else
            {
                flags |= BindingFlags.Instance;
            }
            var method = otype.GetMethod(binder.name, flags);
            if (method != null)
            {
                // setup binding to method
                binder.type     = otype;
                binder.property = null;
                binder.field    = null;
                binder.method   = method;
                // construct method delegate
                return(PlayScript.Dynamic.ConvertValue <T>(Delegate.CreateDelegate(PlayScript.Dynamic.GetDelegateTypeForMethod(binder.method), o, binder.method)));
            }

            if (o is IDynamicClass)
            {
                // dynamic class
                binder.type     = otype;
                binder.property = null;
                binder.field    = null;
                binder.method   = null;
                object result = ((IDynamicClass)o).__GetDynamicValue(binder.name);
                return(PlayScript.Dynamic.ConvertValue <T>(result));
            }

            // could not resolve name as property or field, and is not dynamic class or dictionary
            // invoke callback
            if (Binder.OnGetMemberError != null)
            {
                return(PlayScript.Dynamic.ConvertValue <T>(Binder.OnGetMemberError(o, binder.name, null)));
            }
            else
            {
                return(default(T));
            }
        }
        /// <summary>
        /// This is the most generic method for getting a member's value.
        /// It will attempt to resolve the member by name and the get its value by invoking the
        /// callsite's delegate
        /// </summary>
        public T GetMember <T> (object o)
        {
            Stats.Increment(StatsCounter.GetMemberBinderInvoked);

            TypeLogger.LogType(o);

            // resolve as dictionary (this is usually an expando)
            var dict = o as IDictionary <string, object>;

            if (dict != null)
            {
                Stats.Increment(StatsCounter.GetMemberBinder_Expando);

                // special case this for expando objects
                object value;
                if (dict.TryGetValue(mName, out value))
                {
                    // fast path empty cast just in case
                    if (value is T)
                    {
                        return((T)value);
                    }
                    else
                    {
                        return(PlayScript.Dynamic.ConvertValue <T>(value));
                    }
                }

                // key not found
                return(default(T));
            }

            if (o == null)
            {
                return(default(T));
            }

            // determine if this is a instance member or a static member
            bool isStatic;
            Type otype;

            if (o is System.Type)
            {
                // static member
                otype    = (System.Type)o;
                o        = null;
                isStatic = true;
            }
            else
            {
                // instance member
                otype    = o.GetType();
                isStatic = false;
            }

            if (otype == mType)
            {
                // use cached resolve
                if (mProperty != null)
                {
                    Func <T> func;
                    if (o == mPreviousTarget)
                    {
                        func = (Func <T>)mPreviousFunc;
                    }
                    else
                    {
                        mPreviousFunc   = func = ActionCreator.CreatePropertyGetAction <T>(o, mProperty);
                        mPreviousTarget = o;
                    }
                    return(func());
                }

                if (mField != null)
                {
                    return(PlayScript.Dynamic.ConvertValue <T>(mField.GetValue(o)));
                }

                if (mMethod != null)
                {
                    // construct method delegate
                    return(PlayScript.Dynamic.ConvertValue <T>(Delegate.CreateDelegate(mTargetType, o, mMethod)));
                }

                // resolve as dynamic class
                var dc = o as IDynamicClass;
                if (dc != null)
                {
                    object result = dc.__GetDynamicValue(mName);
                    return(PlayScript.Dynamic.ConvertValue <T>(result));
                }

                throw new System.InvalidOperationException("Unhandled member type in PSGetMemberBinder");
            }

            // resolve name
            Stats.Increment(StatsCounter.GetMemberBinder_Resolve_Invoked);

            // resolve as property
            var property = otype.GetProperty(mName);

            if (property != null)
            {
                // found property
                var getter = property.GetGetMethod();
                if (getter != null && getter.IsPublic && getter.IsStatic == isStatic)
                {
                    // setup binding to property
                    mType           = otype;
                    mPreviousFunc   = null;
                    mPreviousTarget = null;
                    mProperty       = property;
                    mPropertyGetter = property.GetGetMethod();
                    mField          = null;
                    mMethod         = null;
                    mTargetType     = property.PropertyType;
                    return(PlayScript.Dynamic.ConvertValue <T>(mPropertyGetter.Invoke(o, null)));
                }
            }

            // resolve as field
            var field = otype.GetField(mName);

            if (field != null)
            {
                // found field
                if (field.IsPublic && field.IsStatic == isStatic)
                {
                    // setup binding to field
                    mType           = otype;
                    mPreviousFunc   = null;
                    mPreviousTarget = null;
                    mProperty       = null;
                    mField          = field;
                    mMethod         = null;
                    mTargetType     = field.FieldType;
                    return(PlayScript.Dynamic.ConvertValue <T>(field.GetValue(o)));
                }
            }

            // resolve as method
            BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public;

            if (isStatic)
            {
                flags |= BindingFlags.Static;
            }
            else
            {
                flags |= BindingFlags.Instance;
            }
            var method = otype.GetMethod(mName, flags);

            if (method != null)
            {
                // setup binding to method
                mType           = otype;
                mPreviousFunc   = null;
                mPreviousTarget = null;
                mProperty       = null;
                mField          = null;
                mMethod         = method;
                mTargetType     = PlayScript.Dynamic.GetDelegateTypeForMethod(mMethod);

                // construct method delegate
                return(PlayScript.Dynamic.ConvertValue <T>(Delegate.CreateDelegate(mTargetType, o, mMethod)));
            }

            if (o is IDynamicClass)
            {
                // dynamic class
                mType           = otype;
                mPreviousFunc   = null;
                mPreviousTarget = null;
                mProperty       = null;
                mField          = null;
                mMethod         = null;
                object result = ((IDynamicClass)o).__GetDynamicValue(mName);
                return(PlayScript.Dynamic.ConvertValue <T>(result));
            }

            return(default(T));
        }