[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/tlecomte/ClearScript/master/ClearScript/HostVariable.cs [Back]  [Original]

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.Dynamic;
using System.Reflection;
using Microsoft.ClearScript.Util;

namespace Microsoft.ClearScript
{
    internal interface IHostVariable
    {
        Type Type { get; }
        object Value { get; set; }
    }

    internal abstract class HostVariableBase : HostTarget
    {
        private static readonly string[] auxPropertyNames = { "out", "ref", "value" };

        public override string[] GetAuxPropertyNames(IHostInvokeContext context, BindingFlags bindFlags)
        {
            return auxPropertyNames;
        }
    }

    internal sealed class HostVariable : HostVariableBase, IHostVariable
    {
        public HostVariable(T initValue)
        {
            if ((typeof(T) == typeof(Undefined)) || (typeof(T) == typeof(VoidResult)))
            {
                throw new NotSupportedException("Unsupported variable type");
            }

            if (typeof(HostItem).IsAssignableFrom(typeof(T)) || typeof(HostTarget).IsAssignableFrom(typeof(T)))
            {
                throw new NotSupportedException("Unsupported variable type");
            }

            if ((initValue is HostItem) || (initValue is HostTarget))
            {
                throw new NotSupportedException("Unsupported value type");
            }

            Value = initValue;
        }

        public T Value { get; set; }
            // Be careful when renaming or deleting this property; it is accessed by name in the
            // expression tree construction code in DelegateFactory.CreateComplexDelegate().

        #region Object overrides

        public override string ToString()
        {
            var objectName = Value.GetFriendlyName(typeof(T));
            return MiscHelpers.FormatInvariant("HostVariable:{0}", objectName);
        }

        #endregion

        #region HostTarget overrides

        public override Type Type => typeof(T);

        public override object Target => Value;

        public override object InvokeTarget => Value;

        public override object DynamicInvokeTarget => Value;

        public override HostTargetFlags GetFlags(IHostInvokeContext context)
        {
            var flags = HostTargetFlags.AllowInstanceMembers | HostTargetFlags.AllowExtensionMethods;
            if (context.Engine.ExposeHostObjectStaticMembers)
            {
                flags |= HostTargetFlags.AllowStaticMembers;
            }

            return flags;
        }

        public override bool TryInvokeAuxMember(IHostInvokeContext context, string name, BindingFlags invokeFlags, object[] args, object[] bindArgs, out object result)
        {
            const BindingFlags getPropertyFlags =
                BindingFlags.GetField |
                BindingFlags.GetProperty;

            const BindingFlags setPropertyFlags =
                BindingFlags.SetProperty |
                BindingFlags.PutDispProperty |
                BindingFlags.PutRefDispProperty;

            if (name == "out")
            {
                if ((invokeFlags & getPropertyFlags) != 0)
                {
                    result = new OutArg(this);
                    return true;
                }
            }
            else if (name == "ref")
            {
                if ((invokeFlags & getPropertyFlags) != 0)
                {
                    result = new RefArg(this);
                    return true;
                }
            }
            else if (name == "value")
            {
                if (invokeFlags.HasFlag(BindingFlags.InvokeMethod))
                {
                    if (InvokeHelpers.TryInvokeObject(context, Value, invokeFlags, args, bindArgs, typeof(IDynamicMetaObjectProvider).IsAssignableFrom(typeof(T)), out result))
                    {
                        return true;
                    }

                    if (invokeFlags.HasFlag(BindingFlags.GetField) && (args.Length < 1))
                    {
                        result = context.Engine.PrepareResult(Value, ScriptMemberFlags.None, false);
                        return true;
                    }

                    result = null;
                    return false;
                }

                if ((invokeFlags & getPropertyFlags) != 0)
                {
                    result = context.Engine.PrepareResult(Value, ScriptMemberFlags.None, false);
                    return true;
                }

                if ((invokeFlags & setPropertyFlags) != 0)
                {
                    if (args.Length == 1)
                    {
                        result = context.Engine.PrepareResult(((IHostVariable)this).Value = args[0], typeof(T), ScriptMemberFlags.None, false);
                        return true;
                    }
                }
            }

            result = null;
            return false;
        }

        public override Invocability GetInvocability(BindingFlags bindFlags, Type accessContext, ScriptAccess defaultAccess, bool ignoreDynamic)
        {
            return typeof(T).GetInvocability(bindFlags, accessContext, defaultAccess, ignoreDynamic);
        }

        #endregion

        #region IHostVariable implementation

        object IHostVariable.Value
        {
            get => Value;

            set
            {
                if (!typeof(T).IsAssignableFrom(ref value))
                {
                    throw new InvalidOperationException("Assignment invalid due to type mismatch");
                }

                if ((value is HostItem) || (value is HostTarget))
                {
                    throw new NotSupportedException("Unsupported value type");
                }

                Value = (T)value;
            }
        }

        #endregion
    }
}

Web Proxy Viewer  |  New URL  |  Original Page