[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/QPC-database/ClearScript/master/ClearScript/HostFunctions.cs [Back]  [Original]

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

using System;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.ClearScript.Util;
using Microsoft.ClearScript.Util.COM;

namespace Microsoft.ClearScript
{
    /// 
    /// Provides optional script-callable utility functions.
    /// 
    /// 
    /// Use AddHostObject to expose a
    /// HostFunctions instance to script code. Each instance can only be exposed in one
    /// script engine.
    /// 
    public class HostFunctions : IScriptableObject
    {
        private ScriptEngine engine;

        // ReSharper disable EmptyConstructor

        /// 
        /// Initializes a new  instance.
        /// 
        public HostFunctions()
        {
            // the help file builder (SHFB) insists on an empty constructor here
        }

        // ReSharper restore EmptyConstructor

        #region script-callable interface

        // ReSharper disable InconsistentNaming

        /// 
        /// Creates an empty host object.
        /// 
        /// A new empty host object.
        /// 
        /// This function is provided for script languages that do not support external
        /// instantiation. It creates an object that supports dynamic property addition and
        /// removal. The host can manipulate it via the  interface.
        /// 
        /// 
        /// The following code creates an empty host object and adds several properties to it.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var item = host.newObj();
        /// item.label = "Widget";
        /// item.weight = 123.45;
        /// 
        /// 
        public PropertyBag newObj()
        {
            return new PropertyBag();
        }

        /// 
        /// Creates a host object of the specified type. This version is invoked if the specified
        /// type can be used as a type argument.
        /// 
        /// The type of object to create.
        /// Optional constructor arguments.
        /// A new host object of the specified type.
        /// 
        /// 
        /// This function is provided for script languages that do not support external
        /// instantiation. It is overloaded with  and
        /// selected at runtime if  can be used as a type argument.
        /// 
        /// 
        /// For information about the mapping between host members and script-callable properties
        /// and methods, see
        /// AddHostObject.
        /// 
        /// 
        /// 
        /// The following code imports the  class, creates an
        /// instance using the
        /// Random(Int32)
        /// constructor, and calls the  method.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var RandomT = host.type("System.Random");
        /// var random = host.newObj(RandomT, 100);
        /// var value = random.NextDouble();
        /// 
        /// 
        /// 
        public T newObj(params object[] args)
        {
            return (T)typeof(T).CreateInstance(args);
        }

        /// 
        /// Creates a host object of the specified type. This version is invoked if the specified
        /// type cannot be used as a type argument.
        /// 
        /// The type of object to create.
        /// Optional constructor arguments.
        /// A new host object of the specified type.
        /// 
        /// 
        /// This function is provided for script languages that do not support external
        /// instantiation. It is overloaded with  and selected at runtime if
        ///  cannot be used as a type argument. Note that this applies
        /// to some host types that support instantiation, such as certain COM/ActiveX types.
        /// 
        /// 
        /// For information about the mapping between host members and script-callable properties
        /// and methods, see
        /// AddHostObject.
        /// 
        /// 
        public object newObj(object type, params object[] args)
        {
            return GetUniqueHostType(type, "type").CreateInstance(args);
        }

        /// 
        /// Performs dynamic instantiation.
        /// 
        /// The dynamic host object that provides the instantiation operation to perform.
        /// Optional instantiation arguments.
        /// The result of the operation, which is usually a new dynamic host object.
        /// 
        /// This function is provided for script languages that do not support external
        /// instantiation.
        /// 
        public object newObj(IDynamicMetaObjectProvider target, params object[] args)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));

            if (target.GetMetaObject(Expression.Constant(target)).TryCreateInstance(args, out var result))
            {
                return result;
            }

            throw new InvalidOperationException("Invalid dynamic instantiation");
        }

        /// 
        /// Creates a host array with the specified element type.
        /// 
        /// The element type of the array to create.
        /// One or more integers representing the array dimension lengths.
        /// A new host array with the specified element type.
        /// 
        /// For information about the mapping between host members and script-callable properties
        /// and methods, see
        /// AddHostObject.
        /// 
        /// 
        /// The following code creates a 5x3 host array of strings.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var StringT = host.type("System.String");
        /// var array = host.newArr(StringT, 5, 3);
        /// 
        /// 
        /// 
        /// 
        public object newArr(params int[] lengths)
        {
            return Array.CreateInstance(typeof(T), lengths);
        }

        /// 
        /// Creates a host array with  as the element type.
        /// 
        /// One or more integers representing the array dimension lengths.
        /// A new host array with  as the element type.
        /// 
        /// For information about the mapping between host members and script-callable properties
        /// and methods, see
        /// AddHostObject.
        /// 
        /// 
        public object newArr(params int[] lengths)
        {
            return newArr(lengths);
        }

        /// 
        /// Creates a host variable of the specified type.
        /// 
        /// The type of variable to create.
        /// An optional initial value for the variable.
        /// A new host variable of the specified type.
        /// 
        /// 
        /// A host variable is a strongly typed object that holds a value of the specified type.
        /// Host variables are useful for passing method arguments by reference. In addition to
        /// being generally interchangeable with their stored values, host variables support the
        /// following properties:
        /// 
        /// 
        /// 
        ///     
        ///         Property
        ///         Access
        ///         Description
        ///     
        ///     
        ///         value
        ///         read-write
        ///         The current value of the host variable.
        ///     
        ///     
        ///         out
        ///         read-only
        ///         A reference to the host variable that can be passed as an out argument.
        ///     
        ///     
        ///         ref
        ///         read-only
        ///         A reference to the host variable that can be passed as a ref argument.
        ///     
        /// 
        /// 
        /// 
        /// 
        /// The following code demonstrates using a host variable to invoke a method with an
        /// out parameter.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import a dictionary type
        /// var StringT = host.type("System.String");
        /// var StringDictT = host.type("System.Collections.Generic.Dictionary", StringT, StringT);
        /// // create and populate a dictionary
        /// var dict = host.newObj(StringDictT);
        /// dict.Add("foo", "bar");
        /// dict.Add("baz", "qux");
        /// // look up a dictionary entry
        /// var result = host.newVar(StringT);
        /// var found = dict.TryGetValue("baz", result.out);
        /// 
        /// 
        /// 
        public object newVar(T initValue = default)
        {
            return new HostVariable(initValue);
        }

        /// 
        /// Creates a delegate that invokes a script function.
        /// 
        /// The type of delegate to create.
        /// The script function for which to create a delegate.
        /// A new delegate that invokes the specified script function.
        /// 
        /// If the delegate signature includes parameters passed by reference, the corresponding
        /// arguments to the script function will be host variables.
        /// The script function can set the value of an output argument by assigning the
        /// corresponding host variable's value property.
        /// 
        /// 
        /// The following code demonstrates delegating a callback to a script function.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // create and populate an array of integers
        /// var EnumerableT = host.type("System.Linq.Enumerable", "System.Core");
        /// var array = EnumerableT.Range(1, 5).ToArray();
        /// // import the callback type required to call Array.ForEach
        /// var Int32T = host.type("System.Int32");
        /// var CallbackT = host.type("System.Action", Int32T);
        /// // use Array.ForEach to calculate a sum
        /// var sum = 0;
        /// var ArrayT = host.type("System.Array");
        /// ArrayT.ForEach(array, host.del(CallbackT, function (value) { sum += value; }));
        /// 
        /// 
        /// 
        /// 
        public T del(object scriptFunc)
        {
            return DelegateFactory.CreateDelegate(GetEngine(), scriptFunc);
        }

        /// 
        /// Creates a delegate that invokes a script function and returns no value.
        /// 
        /// The number of arguments to pass to the script function.
        /// The script function for which to create a delegate.
        /// A new delegate that invokes the specified script function and returns no value.
        /// 
        /// This function creates a delegate that accepts  arguments and
        /// returns no value. The type of all parameters is . Such a
        /// delegate is often useful in strongly typed contexts because of
        /// contravariance.
        /// 
        /// 
        /// The following code demonstrates delegating a callback to a script function.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // create and populate an array of strings
        /// var StringT = host.type("System.String");
        /// var array = host.newArr(StringT, 3);
        /// array.SetValue("first", 0);
        /// array.SetValue("second", 1);
        /// array.SetValue("third", 2);
        /// // use Array.ForEach to generate console output
        /// var ArrayT = host.type("System.Array");
        /// var ConsoleT = host.type("System.Console");
        /// ArrayT.ForEach(array, host.proc(1, function (value) { ConsoleT.WriteLine(value); }));
        /// 
        /// 
        /// 
        /// 
        public object proc(int argCount, object scriptFunc)
        {
            return DelegateFactory.CreateProc(GetEngine(), scriptFunc, argCount);
        }

        /// 
        /// Creates a delegate that invokes a script function and returns a value of the specified type.
        /// 
        /// The return value type.
        /// The number of arguments to pass to the script function.
        /// The script function for which to create a delegate.
        /// A new delegate that invokes the specified script function and returns a value of the specified type.
        /// 
        /// This function creates a delegate that accepts  arguments and
        /// returns a value of the specified type. The type of all parameters is
        /// . Such a delegate is often useful in strongly typed contexts
        /// because of
        /// contravariance.
        /// 
        /// 
        /// The following code demonstrates delegating a callback to a script function.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // create and populate an array of strings
        /// var StringT = host.type("System.String");
        /// var array = host.newArr(StringT, 3);
        /// array.SetValue("first", 0);
        /// array.SetValue("second", 1);
        /// array.SetValue("third", 2);
        /// // import LINQ extensions
        /// var EnumerableT = host.type("System.Linq.Enumerable", "System.Core");
        /// // use LINQ to create an array of modified strings
        /// var selector = host.func(StringT, 1, function (value) { return value.toUpperCase(); });
        /// array = array.Select(selector).ToArray();
        /// 
        /// 
        /// 
        /// 
        /// 
        public object func(int argCount, object scriptFunc)
        {
            return DelegateFactory.CreateFunc(GetEngine(), scriptFunc, argCount);
        }

        /// 
        /// Creates a delegate that invokes a script function and returns its result value.
        /// 
        /// The number of arguments to pass to the script function.
        /// The script function for which to create a delegate.
        /// A new delegate that invokes the specified script function and returns its result value.
        /// 
        /// 
        /// This function creates a delegate that accepts  arguments and
        /// returns the result of invoking . The type of all
        /// parameters and the return value is . Such a delegate is
        /// often useful in strongly typed contexts because of
        /// contravariance.
        /// 
        /// 
        /// For information about the types of result values that script code can return, see
        /// .
        /// 
        /// 
        /// 
        public object func(int argCount, object scriptFunc)
        {
            return func(argCount, scriptFunc);
        }

        /// 
        /// Gets the  for the specified host type. This version is invoked
        /// if the specified object can be used as a type argument.
        /// 
        /// The host type for which to get the .
        /// The  for the specified host type.
        /// 
        /// 
        /// This function is similar to C#'s
        /// typeof
        /// operator. It is overloaded with  and selected at runtime if
        ///  can be used as a type argument.
        /// 
        /// 
        /// This function throws an exception if the script engine's
        ///  property is set to false.
        /// 
        /// 
        /// 
        /// The following code retrieves the assembly-qualified name of a host type.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var StringT = host.type("System.String");
        /// var name = host.typeOf(StringT).AssemblyQualifiedName;
        /// 
        /// 
        /// 
        public Type typeOf()
        {
            GetEngine().CheckReflection();
            return typeof(T);
        }

        /// 
        /// Gets the  for the specified host type. This version is invoked
        /// if the specified object cannot be used as a type argument.
        /// 
        /// The host type for which to get the .
        /// The  for the specified host type.
        /// 
        /// 
        /// This function is similar to C#'s
        /// typeof
        /// operator. It is overloaded with  and selected at runtime if
        ///  cannot be used as a type argument. Note that this applies to
        /// some host types; examples are static types and overloaded generic type groups.
        /// 
        /// 
        /// This function throws an exception if the script engine's
        ///  property is set to false.
        /// 
        /// 
        /// 
        /// The following code retrieves the assembly-qualified name of a host type.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var ConsoleT = host.type("System.Console");
        /// var name = host.typeOf(ConsoleT).AssemblyQualifiedName;
        /// 
        /// 
        /// 
        public Type typeOf(object value)
        {
            GetEngine().CheckReflection();
            return GetUniqueHostType(value, "value");
        }

        /// 
        /// Determines whether an object is compatible with the specified host type.
        /// 
        /// The host type with which to test  for compatibility.
        /// The object to test for compatibility with the specified host type.
        /// True if  is compatible with the specified type, false otherwise.
        /// 
        /// This function is similar to C#'s
        /// is
        /// operator.
        /// 
        /// 
        /// The following code defines a function that determines whether an object implements
        /// .
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// function isComparable(value)
        /// {
        ///     var IComparableT = host.type("System.IComparable");
        ///     return host.isType(IComparableT, value);
        /// }
        /// 
        /// 
        /// 
        public bool isType(object value)
        {
            return value is T;
        }

        /// 
        /// Casts an object to the specified host type, returning null if the cast fails.
        /// 
        /// The host type to which to cast .
        /// The object to cast to the specified host type.
        /// The result of the cast if successful, null otherwise.
        /// 
        /// This function is similar to C#'s
        /// as
        /// operator.
        /// 
        /// 
        /// The following code defines a function that disposes an object if it implements
        /// .
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// function dispose(value)
        /// {
        ///     var IDisposableT = host.type("System.IDisposable");
        ///     var disposable = host.asType(IDisposableT, value);
        ///     if (disposable) {
        ///         disposable.Dispose();
        ///     }
        /// }
        /// 
        /// 
        /// 
        public object asType(object value) where T : class
        {
            return HostItem.Wrap(GetEngine(), value as T, typeof(T));
        }

        /// 
        /// Casts an object to the specified host type.
        /// 
        /// The host type to which to cast .
        /// The object to cast to the specified host type.
        /// The result of the cast.
        /// 
        /// If the cast fails, this function throws an exception.
        /// 
        /// 
        /// The following code casts a floating-point value to a 32-bit integer.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var Int32T = host.type("System.Int32");
        /// var intValue = host.cast(Int32T, 12.5);
        /// 
        /// 
        /// 
        public object cast(object value)
        {
            return HostItem.Wrap(GetEngine(), value.DynamicCast(), typeof(T));
        }

        /// 
        /// Determines whether an object is a host type. This version is invoked if the specified
        /// object cannot be used as a type argument.
        /// 
        /// The object to test.
        /// True if  is a host type, false otherwise.
        /// 
        /// This function is overloaded with  and selected at runtime if
        ///  cannot be used as a type argument. Note that this applies to
        /// some host types; examples are static types and overloaded generic type groups.
        /// 
        public bool isTypeObj(object value)
        {
            return value is HostType;
        }

        // ReSharper disable UnusedTypeParameter

        /// 
        /// Determines whether an object is a host type. This version is invoked if the specified
        /// object can be used as a type argument.
        /// 
        /// The host type (ignored).
        /// True.
        /// 
        /// This function is overloaded with  and selected at
        /// runtime if  can be used as a type argument. Because type
        /// arguments are always host types, this method ignores its type argument and always
        /// returns true.
        /// 
        public bool isTypeObj()
        {
            return true;
        }

        // ReSharper restore UnusedTypeParameter

        /// 
        /// Determines whether the specified value is null.
        /// 
        /// The value to test.
        /// True if  is null, false otherwise.
        /// 
        /// Use this function to test field, property, and method return values when null
        /// result wrapping is in effect (see 
        ///  and
        /// ).
        /// 
        /// 
        /// 
        public bool isNull(object value)
        {
            return value == null;
        }

        /// 
        /// Creates a strongly typed flag set.
        /// 
        /// The type of flag set to create.
        /// The flags to include in the flag set.
        /// A strongly typed flag set containing the specified flags.
        /// 
        /// This function throws an exception if  is not a flag set type.
        /// 
        /// 
        /// The following code demonstrates using a strongly typed flag set.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import URI types
        /// var UriT = host.type("System.Uri", "System");
        /// var UriFormatT = host.type("System.UriFormat", "System");
        /// var UriComponentsT = host.type("System.UriComponents", "System");
        /// // create a URI
        /// var uri = host.newObj(UriT, "http://www.example.com:8080/path/to/file/sample.htm?x=1&y=2");
        /// // extract URI components
        /// var components = host.flags(UriComponentsT.Scheme, UriComponentsT.Host, UriComponentsT.Path);
        /// var result = uri.GetComponents(components, UriFormatT.Unescaped);
        /// 
        /// 
        /// 
        public T flags(params T[] args)
        {
            var type = typeof(T);
            if (!type.IsFlagsEnum())
            {
                throw new InvalidOperationException(MiscHelpers.FormatInvariant("{0} is not a flag set type", type.GetFullFriendlyName()));
            }

            try
            {
                return args.Aggregate(0UL, (flags, arg) => flags | Convert.ToUInt64(arg, CultureInfo.InvariantCulture)).DynamicCast();
            }
            catch (OverflowException)
            {
                return args.Aggregate(0L, (flags, arg) => flags | Convert.ToInt64(arg, CultureInfo.InvariantCulture)).DynamicCast();
            }
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.SByte");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toSByte(42));
        /// 
        /// 
        /// 
        public object toSByte(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToSByte(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.Byte");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toByte(42));
        /// 
        /// 
        /// 
        public object toByte(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToByte(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.Int16");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toInt16(42));
        /// 
        /// 
        /// 
        public object toInt16(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToInt16(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.UInt16");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toUInt16(42));
        /// 
        /// 
        /// 
        public object toUInt16(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToUInt16(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.Char");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toChar(42));
        /// 
        /// 
        /// 
        public object toChar(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToChar(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.Int32");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toInt32(42));
        /// 
        /// 
        /// 
        public object toInt32(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToInt32(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.UInt32");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toUInt32(42));
        /// 
        /// 
        /// 
        public object toUInt32(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToUInt32(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.Int64");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toInt64(42));
        /// 
        /// 
        /// 
        public object toInt64(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToInt64(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.UInt64");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toUInt64(42));
        /// 
        /// 
        /// 
        public object toUInt64(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToUInt64(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.Single");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toSingle(42));
        /// 
        /// 
        /// 
        public object toSingle(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToSingle(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.Double");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toDouble(42));
        /// 
        /// 
        /// 
        public object toDouble(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToDouble(value));
        }

        /// 
        /// Converts the specified value to a strongly typed  instance.
        /// 
        /// The value to convert.
        /// An object that can be passed to a parameter of type .
        /// 
        /// This function converts  to  and
        /// packages the result to retain its numeric type across the host-script boundary. It may
        /// be useful for passing arguments to  parameters if the script
        /// engine does not support that type natively.
        /// 
        /// 
        /// The following code adds an element of type  to a strongly
        /// typed list.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ElementT = host.type("System.Decimal");
        /// var ListT = host.type("System.Collections.Generic.List", ElementT);
        /// // create a list
        /// var list = host.newObj(ListT);
        /// // add a list element
        /// list.Add(host.toDecimal(42));
        /// 
        /// 
        /// 
        public object toDecimal(IConvertible value)
        {
            return HostObject.Wrap(Convert.ToDecimal(value));
        }

        /// 
        /// Gets the value of a property in a dynamic host object that implements .
        /// 
        /// The dynamic host object that contains the property to get.
        /// The name of the property to get.
        /// The value of the specified property.
        /// 
        /// This function is provided for script languages that do not support dynamic properties.
        /// 
        public object getProperty(IPropertyBag target, string name)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));

            if (target.TryGetValue(name, out var result))
            {
                return result;
            }

            return Nonexistent.Value;
        }

        /// 
        /// Sets a property value in a dynamic host object that implements .
        /// 
        /// The dynamic host object that contains the property to set.
        /// The name of the property to set.
        /// The new value of the specified property.
        /// The result of the operation, which is usually the value assigned to the specified property.
        /// 
        /// This function is provided for script languages that do not support dynamic properties.
        /// 
        public object setProperty(IPropertyBag target, string name, object value)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));
            return target[name] = value;
        }

        /// 
        /// Removes a property from a dynamic host object that implements .
        /// 
        /// The dynamic host object that contains the property to remove.
        /// The name of the property to remove.
        /// True if the property was found and removed, false otherwise.
        /// 
        /// This function is provided for script languages that do not support dynamic properties.
        /// 
        public bool removeProperty(IPropertyBag target, string name)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));
            return target.Remove(name);
        }

        /// 
        /// Gets the value of a property in a dynamic host object that implements .
        /// 
        /// The dynamic host object that contains the property to get.
        /// The name of the property to get.
        /// The value of the specified property.
        /// 
        /// This function is provided for script languages that do not support dynamic properties.
        /// 
        public object getProperty(IDynamicMetaObjectProvider target, string name)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));

            if (target.GetMetaObject(Expression.Constant(target)).TryGetMember(name, out var result))
            {
                return result;
            }

            return Nonexistent.Value;
        }

        /// 
        /// Sets a property value in a dynamic host object that implements .
        /// 
        /// The dynamic host object that contains the property to set.
        /// The name of the property to set.
        /// The new value of the specified property.
        /// The result of the operation, which is usually the value assigned to the specified property.
        /// 
        /// This function is provided for script languages that do not support dynamic properties.
        /// 
        public object setProperty(IDynamicMetaObjectProvider target, string name, object value)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));

            if (target.GetMetaObject(Expression.Constant(target)).TrySetMember(name, value, out var result))
            {
                return result;
            }

            throw new InvalidOperationException("Invalid dynamic property assignment");
        }

        /// 
        /// Removes a property from a dynamic host object that implements .
        /// 
        /// The dynamic host object that contains the property to remove.
        /// The name of the property to remove.
        /// True if the property was found and removed, false otherwise.
        /// 
        /// This function is provided for script languages that do not support dynamic properties.
        /// 
        public bool removeProperty(IDynamicMetaObjectProvider target, string name)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));

            if (target.GetMetaObject(Expression.Constant(target)).TryDeleteMember(name, out var result))
            {
                return result;
            }

            throw new InvalidOperationException("Invalid dynamic property deletion");
        }

        /// 
        /// Gets the value of an element in a dynamic host object that implements .
        /// 
        /// The dynamic host object that contains the element to get.
        /// One or more indices that identify the element to get.
        /// The value of the specified element.
        /// 
        /// This function is provided for script languages that do not support general indexing.
        /// 
        public object getElement(IDynamicMetaObjectProvider target, params object[] indices)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));

            if (target.GetMetaObject(Expression.Constant(target)).TryGetIndex(indices, out var result))
            {
                return result;
            }

            return Nonexistent.Value;

        }

        /// 
        /// Sets an element value in a dynamic host object that implements .
        /// 
        /// The dynamic host object that contains the element to set.
        /// The new value of the element.
        /// One or more indices that identify the element to set.
        /// The result of the operation, which is usually the value assigned to the specified element.
        /// 
        /// This function is provided for script languages that do not support general indexing.
        /// 
        public object setElement(IDynamicMetaObjectProvider target, object value, params object[] indices)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));

            if (target.GetMetaObject(Expression.Constant(target)).TrySetIndex(indices, value, out var result))
            {
                return result;
            }

            throw new InvalidOperationException("Invalid dynamic element assignment");
        }

        /// 
        /// Removes an element from a dynamic host object that implements .
        /// 
        /// The dynamic host object that contains the element to remove.
        /// One or more indices that identify the element to remove.
        /// True if the element was found and removed, false otherwise.
        /// 
        /// This function is provided for script languages that do not support general indexing.
        /// 
        public bool removeElement(IDynamicMetaObjectProvider target, params object[] indices)
        {
            MiscHelpers.VerifyNonNullArgument(target, nameof(target));

            if (target.GetMetaObject(Expression.Constant(target)).TryDeleteIndex(indices, out var result))
            {
                return result;
            }

            throw new InvalidOperationException("Invalid dynamic element deletion");
        }

        /// 
        /// Casts a dynamic host object to its static type.
        /// 
        /// The object to cast to its static type.
        /// The specified object in its static type form, stripped of its dynamic members.
        /// 
        /// A dynamic host object that implements  may have
        /// dynamic members that override members of its static type. This function can be used to
        /// gain access to type members overridden in this manner.
        /// 
        public object toStaticType(IDynamicMetaObjectProvider value)
        {
            return HostItem.Wrap(GetEngine(), value, HostItemFlags.HideDynamicMembers);
        }

        /// 
        /// Allows script code to handle host exceptions.
        /// 
        /// A script function that invokes one or more host methods or properties.
        /// A script function to invoke if  throws an exception.
        /// An optional script function that performs cleanup for the operation.
        /// True if  completed successfully, false if it threw an exception that was handled by .
        /// 
        /// This function uses a try-catch-finally statement to invoke
        /// . If an exception is thrown, it is caught and passed to
        ///  for analysis. If  returns
        /// false, the exception is rethrown. Regardless of the outcome,
        /// , if specified, is invoked as a final step before the
        /// function exits.
        /// 
        /// 
        /// The following code demonstrates handling host exceptions in script code.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// // import types
        /// var ConsoleT = host.type("System.Console");
        /// var WebClientT = host.type("System.Net.WebClient", "System");
        /// // create a Web client
        /// var webClient = host.newObj(WebClientT);
        /// host.tryCatch(
        ///     function () {
        ///         // download Web document
        ///         ConsoleT.WriteLine(webClient.DownloadString("http://cnn.com"));
        ///     },
        ///     function (exception) {
        ///         // dump exception
        ///         ConsoleT.WriteLine("*** ERROR: " + exception.GetBaseException().ToString());
        ///         return true;
        ///     },
        ///     function () {
        ///         // clean up
        ///         ConsoleT.WriteLine("*** CLEANING UP ***");
        ///         webClient.Dispose();
        ///     }
        /// );
        /// 
        /// 
        /// 
        /// 
        public bool tryCatch(object tryFunc, object catchFunc, object finallyFunc = null)
        {
            MiscHelpers.VerifyNonNullArgument(tryFunc, nameof(tryFunc));
            MiscHelpers.VerifyNonNullArgument(catchFunc, nameof(catchFunc));

            try
            {
                ((dynamic)tryFunc)();
                return true;
            }
            catch (Exception exception)
            {
                if (!((dynamic)catchFunc)(exception))
                {
                    throw;
                }

                return false;
            }
            finally
            {
                if (finallyFunc != null)
                {
                    ((dynamic)finallyFunc)();
                }
            }
        }

        // ReSharper restore InconsistentNaming

        #endregion

        internal ScriptEngine GetEngine()
        {
            var activeEngine = ScriptEngine.Current ?? engine;
            if (activeEngine == null)
            {
                throw new InvalidOperationException("Operation requires a script engine");
            }

            return activeEngine;
        }

        internal static Type GetUniqueHostType(object type, string paramName)
        {
            var hostType = type as HostType;
            if (hostType == null)
            {
                throw new ArgumentException("Invalid host type", paramName);
            }

            if (hostType.Types.Length > 1)
            {
                throw new ArgumentException(MiscHelpers.FormatInvariant("'{0}' does not identify a unique host type", hostType.Types[0].GetLocator()), paramName);
            }

            return hostType.Types[0];
        }

        #region IScriptableObject implementation

        // ReSharper disable ParameterHidesMember

        [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "This member is not expected to be re-implemented in derived classes.")]
        void IScriptableObject.OnExposedToScriptCode(ScriptEngine engine)
        {
            MiscHelpers.VerifyNonNullArgument(engine, nameof(engine));
            this.engine = engine;
        }

        // ReSharper restore ParameterHidesMember

        #endregion
    }

    /// 
    /// Provides optional script-callable utility functions. This extended version allows script
    /// code to import host types.
    /// 
    public class ExtendedHostFunctions : HostFunctions
    {
        // ReSharper disable EmptyConstructor

        /// 
        /// Initializes a new  instance.
        /// 
        public ExtendedHostFunctions()
        {
            // the help file builder (SHFB) insists on an empty constructor here
        }

        // ReSharper restore EmptyConstructor

        #region script-callable interface

        // ReSharper disable InconsistentNaming

        /// 
        /// Imports a host type by name.
        /// 
        /// The fully qualified name of the host type to import.
        /// Optional generic type arguments.
        /// The imported host type.
        /// 
        /// 
        /// Host types are imported in the form of objects whose properties and methods are bound
        /// to the host type's static members and nested types. If  refers
        /// to a generic type, the corresponding object will be invocable with type arguments to
        /// yield a specific type.
        /// 
        /// 
        /// For more information about the mapping between host members and script-callable
        /// properties and methods, see
        /// AddHostObject.
        /// 
        /// 
        /// 
        /// The following code imports the
        /// Dictionary
        /// generic type and uses it to create a string dictionary.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var DictT = host.type("System.Collections.Generic.Dictionary");
        /// var StringT = host.type("System.String");
        /// var dict = host.newObj(DictT(StringT, StringT));
        /// 
        /// Another way to create a string dictionary is to import the specific type directly.
        /// 
        /// var StringT = host.type("System.String");
        /// var StringDictT = host.type("System.Collections.Generic.Dictionary", StringT, StringT);
        /// var dict = host.newObj(StringDictT);
        /// 
        /// 
        public object type(string name, params object[] hostTypeArgs)
        {
            return TypeHelpers.ImportType(name, null, false, hostTypeArgs);
        }

        /// 
        /// Imports a host type by name from the specified assembly.
        /// 
        /// The fully qualified name of the host type to import.
        /// The name of the assembly that contains the host type to import.
        /// Optional generic type arguments.
        /// The imported host type.
        /// 
        /// 
        /// Host types are imported in the form of objects whose properties and methods are bound
        /// to the host type's static members and nested types. If  refers
        /// to a generic type, the corresponding object will be invocable with type arguments to
        /// yield a specific type.
        /// 
        /// 
        /// For more information about the mapping between host members and script-callable
        /// properties and methods, see
        /// AddHostObject.
        /// 
        /// 
        /// 
        /// The following code imports  and uses it to create
        /// an array of strings.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var EnumerableT = host.type("System.Linq.Enumerable", "System.Core");
        /// var Int32T = host.type("System.Int32");
        /// var StringT = host.type("System.String");
        /// var SelectorT = host.type("System.Func", Int32T, StringT);
        /// var selector = host.del(SelectorT, function (num) { return StringT.Format("The number is {0}.", num); });
        /// var array = EnumerableT.Range(0, 5).Select(selector).ToArray();
        /// 
        /// 
        /// 
        public object type(string name, string assemblyName, params object[] hostTypeArgs)
        {
            return TypeHelpers.ImportType(name, assemblyName, true, hostTypeArgs);
        }

        /// 
        /// Imports the host type for the specified .
        /// 
        /// The  that specifies the host type to import.
        /// The imported host type.
        /// 
        /// 
        /// Host types are imported in the form of objects whose properties and methods are bound
        /// to the host type's static members and nested types. If  refers
        /// to a generic type, the corresponding object will be invocable with type arguments to
        /// yield a specific type.
        /// 
        /// 
        /// For more information about the mapping between host members and script-callable
        /// properties and methods, see
        /// AddHostObject.
        /// 
        /// 
        public object type(Type type)
        {
            return HostType.Wrap(type);
        }

        /// 
        /// Imports the host array type for the specified element type.
        /// 
        /// The element type for the host array type to import.
        /// The number of dimensions for the host array type to import.
        /// The imported host array type.
        public object arrType(int rank = 1)
        {
            return HostType.Wrap(typeof(T).MakeArrayType(rank));
        }

        /// 
        /// Imports types from one or more host assemblies.
        /// 
        /// The names of the assemblies that contain the types to import.
        /// The imported host type collection.
        /// 
        /// Host type collections provide convenient scriptable access to all the types defined in one
        /// or more host assemblies. They are hierarchical collections where leaf nodes represent types
        /// and parent nodes represent namespaces. For example, if an assembly contains a type named
        /// "Acme.Gadgets.Button", the corresponding collection will have a property named "Acme" whose
        /// value is an object with a property named "Gadgets" whose value is an object with a property
        /// named "Button" whose value represents the Acme.Gadgets.Button host type.
        /// 
        /// 
        /// The following code imports types from several core assemblies and uses
        ///  to create an array of integers.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var clr = host.lib("mscorlib", "System", "System.Core");
        /// var array = clr.System.Linq.Enumerable.Range(0, 5).ToArray();
        /// 
        /// 
        public HostTypeCollection lib(params string[] assemblyNames)
        {
            return lib(null, assemblyNames);
        }

        /// 
        /// Imports types from one or more host assemblies and merges them with an existing host type collection.
        /// 
        /// The host type collection with which to merge types from the specified assemblies.
        /// The names of the assemblies that contain the types to import.
        /// A host type collection:  if it is not null, a new host type collection otherwise.
        /// 
        /// Host type collections provide convenient scriptable access to all the types defined in one
        /// or more host assemblies. They are hierarchical collections where leaf nodes represent types
        /// and parent nodes represent namespaces. For example, if an assembly contains a type named
        /// "Acme.Gadgets.Button", the corresponding collection will have a property named "Acme" whose
        /// value is an object with a property named "Gadgets" whose value is an object with a property
        /// named "Button" whose value represents the Acme.Gadgets.Button host type.
        /// 
        /// 
        /// The following code imports types from several core assemblies and uses
        ///  to create an array of integers.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var clr = host.lib("mscorlib");
        /// host.lib(clr, "System");
        /// host.lib(clr, "System.Core");
        /// var array = clr.System.Linq.Enumerable.Range(0, 5).ToArray();
        /// 
        /// 
        public HostTypeCollection lib(HostTypeCollection collection, params string[] assemblyNames)
        {
            var target = collection ?? new HostTypeCollection();
            Array.ForEach(assemblyNames, target.AddAssembly);
            return target;
        }

        /// 
        /// Imports a COM/ActiveX type.
        /// 
        /// The programmatic identifier (ProgID) of the registered class to import.
        /// An optional name that specifies the server from which to import the type.
        /// The imported COM/ActiveX type.
        /// 
        /// The  argument can be a class identifier (CLSID) in standard
        /// GUID format with braces (e.g., "{0D43FE01-F093-11CF-8940-00A0C9054228}").
        /// 
        /// 
        /// The following code imports the
        /// Scripting.Dictionary
        /// class and uses it to create and populate an instance.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var DictT = host.comType('Scripting.Dictionary');
        /// var dict = host.newObj(DictT);
        /// dict.Add('foo', 123);
        /// dict.Add('bar', 456.789);
        /// dict.Add('baz', 'abc');
        /// 
        /// 
        public object comType(string progID, string serverName = null)
        {
            return HostType.Wrap(MiscHelpers.GetCOMType(progID, serverName));
        }

        /// 
        /// Creates a COM/ActiveX object of the specified type.
        /// 
        /// The programmatic identifier (ProgID) of the registered class to instantiate.
        /// An optional name that specifies the server on which to create the object.
        /// A new COM/ActiveX object of the specified type.
        /// 
        /// The  argument can be a class identifier (CLSID) in standard
        /// GUID format with braces (e.g., "{0D43FE01-F093-11CF-8940-00A0C9054228}").
        /// 
        /// 
        /// The following code creates a 
        /// Scripting.FileSystemObject
        /// instance and uses it to list the drives on the local machine.
        /// It assumes that an instance of  is exposed under
        /// the name "host"
        /// (see AddHostObject).
        /// 
        /// var fso = host.newComObj('Scripting.FileSystemObject');
        /// var ConsoleT = host.type('System.Console');
        /// for (en = fso.Drives.GetEnumerator(); en.MoveNext();) {
        ///     ConsoleT.WriteLine(en.Current.Path);
        /// }
        /// 
        /// 
        public object newComObj(string progID, string serverName = null)
        {
            return MiscHelpers.CreateCOMObject(progID, serverName);
        }

        /// 
        /// Imports enumerations defined within or referenced from a COM/ActiveX type library.
        /// 
        /// The imported type whose parent library is to be searched for relevant enumerations.
        /// An instance of the representative type.
        /// An optional host type collection with which to merge the imported enumerations.
        /// A host type collection:  if it is not null, a new host type collection otherwise.
        public HostTypeCollection typeLibEnums(T obj, HostTypeCollection collection = null) where T : class
        {
            MiscHelpers.VerifyNonNullArgument(obj, nameof(obj));
            if (collection == null)
            {
                collection = new HostTypeCollection();
            }

            var type = typeof(T);
            if (type.IsUnknownCOMObject())
            {
                if (obj is IDispatch dispatch)
                {
                    var typeInfo = dispatch.GetTypeInfo();
                    if (typeInfo != null)
                    {
                        typeInfo.GetContainingTypeLib().GetReferencedEnums().ForEach(collection.AddEnumTypeInfo);
                        return collection;
                    }
                }
            }
            else if (type.IsImport && (type.Assembly.GetCustomAttribute(typeof(ImportedFromTypeLibAttribute)) != null))
            {
                type.Assembly.GetReferencedEnums().ForEach(collection.AddType);
                return collection;
            }

            throw new ArgumentException("The object type is not of an imported (COM/ActiveX) type", nameof(obj));
        }

        // ReSharper restore InconsistentNaming

        #endregion
    }
}

Web Proxy Viewer  |  New URL  |  Original Page