/// <summary>
		/// Initializes a new instance of the <see cref="ArrayMemberDescriptor"/> class.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="isSetter">if set to <c>true</c> is a setter indexer.</param>
		/// <param name="indexerParams">The indexer parameters.</param>
		public ArrayMemberDescriptor(string name, bool isSetter, ParameterDescriptor[] indexerParams)
			: base(
			name,
			isSetter ? (Func<object, ScriptExecutionContext, CallbackArguments, object>)ArrayIndexerSet : (Func<object, ScriptExecutionContext, CallbackArguments, object>)ArrayIndexerGet,
			indexerParams)
		{
			m_IsSetter = isSetter;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="MethodMemberDescriptor"/> class.
		/// </summary>
		/// <param name="methodBase">The MethodBase (MethodInfo or ConstructorInfo) got through reflection.</param>
		/// <param name="accessMode">The interop access mode.</param>
		/// <exception cref="System.ArgumentException">Invalid accessMode</exception>
		public MethodMemberDescriptor(MethodBase methodBase, InteropAccessMode accessMode = InteropAccessMode.Default)
		{
			CheckMethodIsCompatible(methodBase, true);

			IsConstructor = (methodBase is ConstructorInfo);
			this.MethodInfo = methodBase;

			bool isStatic = methodBase.IsStatic || IsConstructor;

			if (IsConstructor)
				m_IsAction = false;
			else
				m_IsAction = ((MethodInfo)methodBase).ReturnType == typeof(void);

			ParameterInfo[] reflectionParams = methodBase.GetParameters();
			ParameterDescriptor[] parameters;
			
			if (this.MethodInfo.DeclaringType.IsArray)
			{
				m_IsArrayCtor = true;

				int rank = this.MethodInfo.DeclaringType.GetArrayRank();

				parameters = new ParameterDescriptor[rank];

				for (int i = 0; i < rank; i++)
					parameters[i] = new ParameterDescriptor("idx" + i.ToString(), typeof(int));
			}
			else
			{
				parameters = reflectionParams.Select(pi => new ParameterDescriptor(pi)).ToArray();
			}
		
			
			bool isExtensionMethod = (methodBase.IsStatic && parameters.Length > 0 && methodBase.GetCustomAttributes(typeof(ExtensionAttribute), false).Any());

			base.Initialize(methodBase.Name, isStatic, parameters, isExtensionMethod);

			// adjust access mode
			if (Script.GlobalOptions.Platform.IsRunningOnAOT())
				accessMode = InteropAccessMode.Reflection;

			if (accessMode == InteropAccessMode.Default)
				accessMode = UserData.DefaultAccessMode;

			if (accessMode == InteropAccessMode.HideMembers)
				throw new ArgumentException("Invalid accessMode");

			if (parameters.Any(p => p.Type.IsByRef))
				accessMode = InteropAccessMode.Reflection;

			this.AccessMode = accessMode;

			if (AccessMode == InteropAccessMode.Preoptimized)
				((IOptimizableDescriptor)this).Optimize();
		}
        /// <summary>
        ///     Initializes a new instance of the
        ///     <see cref="MethodMemberDescriptor" /> class
        ///     representing the default empty ctor for a value type.
        /// </summary>
        /// <param name="valueType">Type of the value.</param>
        /// <exception cref="System.ArgumentException">valueType is not a value type</exception>
        public ValueTypeDefaultCtorMemberDescriptor(Type valueType)
        {
            if (!valueType.IsValueType)
                throw new ArgumentException("valueType is not a value type");

            Name = "__new";
            Parameters = new ParameterDescriptor[0];

            ValueTypeDefaultCtor = valueType;
        }
		/// <summary>
		/// Initializes this instance.
		/// This *MUST* be called by the constructors extending this class to complete initialization.
		/// </summary>
		/// <param name="funcName">Name of the function.</param>
		/// <param name="isStatic">if set to <c>true</c> [is static].</param>
		/// <param name="parameters">The parameters.</param>
		/// <param name="isExtensionMethod">if set to <c>true</c> [is extension method].</param>
		protected void Initialize(string funcName, bool isStatic, ParameterDescriptor[] parameters, bool isExtensionMethod)
		{
			this.Name = funcName;
			this.IsStatic = isStatic;
			this.Parameters = parameters;

			if (isExtensionMethod)
				this.ExtensionMethodType = Parameters[0].Type;

			if (Parameters.Length > 0 && Parameters[Parameters.Length - 1].IsVarArgs)
			{
				VarArgsArrayType = Parameters[Parameters.Length - 1].Type;
				VarArgsElementType = Parameters[Parameters.Length - 1].Type.GetElementType();
			}

			SortDiscriminant = string.Join(":", Parameters.Select(pi => pi.Type.FullName).ToArray());
		}
		/// <summary>
		/// Fills the member list.
		/// </summary>
		private void FillMemberList()
		{
			HashSet<string> membersToIgnore = new HashSet<string>(
				this.Type
					.GetCustomAttributes(typeof(MoonSharpHideMemberAttribute), true)
					.OfType<MoonSharpHideMemberAttribute>()
					.Select(a => a.MemberName)
				);

			Type type = this.Type;
			var accessMode = this.AccessMode;

			if (AccessMode == InteropAccessMode.HideMembers)
				return;

			// add declared constructors
			foreach (ConstructorInfo ci in type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
			{
				if (membersToIgnore.Contains("__new"))
					continue;

				AddMember("__new", MethodMemberDescriptor.TryCreateIfVisible(ci, this.AccessMode));
			}

			// valuetypes don't reflect their empty ctor.. actually empty ctors are a perversion, we don't care and implement ours
			if (type.IsValueType && !membersToIgnore.Contains("__new"))
				AddMember("__new", new ValueTypeDefaultCtorMemberDescriptor(type));


			// add methods to method list and metamethods
			foreach (MethodInfo mi in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
			{
				if (membersToIgnore.Contains(mi.Name)) continue;

				MethodMemberDescriptor md = MethodMemberDescriptor.TryCreateIfVisible(mi, this.AccessMode);

				if (md != null)
				{
					if (!MethodMemberDescriptor.CheckMethodIsCompatible(mi, false))
						continue;

					// transform explicit/implicit conversions to a friendlier name.
					string name = mi.Name;
					if (mi.IsSpecialName && (mi.Name == SPECIALNAME_CAST_EXPLICIT || mi.Name == SPECIALNAME_CAST_IMPLICIT))
					{
						name = mi.ReturnType.GetConversionMethodName();
					}

					AddMember(name, md);

					foreach (string metaname in mi.GetMetaNamesFromAttributes())
					{
						AddMetaMember(metaname, md);
					}
				}
			}

			// get properties
			foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
			{
				if (pi.IsSpecialName || pi.GetIndexParameters().Any() || membersToIgnore.Contains(pi.Name))
					continue;

				AddMember(pi.Name, PropertyMemberDescriptor.TryCreateIfVisible(pi, this.AccessMode));
			}

			// get fields
			foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
			{
				if (fi.IsSpecialName || membersToIgnore.Contains(fi.Name))
					continue;

				AddMember(fi.Name, FieldMemberDescriptor.TryCreateIfVisible(fi, this.AccessMode));
			}

			// get events
			foreach (EventInfo ei in type.GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
			{
				if (ei.IsSpecialName || membersToIgnore.Contains(ei.Name))
					continue;

				AddMember(ei.Name, EventMemberDescriptor.TryCreateIfVisible(ei, this.AccessMode));
			}

			// get nested types and create statics
			foreach (Type nestedType in type.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public))
			{
				if (membersToIgnore.Contains(nestedType.Name))
					continue;

				if (!nestedType.IsGenericTypeDefinition)
				{
					if (nestedType.IsNestedPublic || nestedType.GetCustomAttributes(typeof(MoonSharpUserDataAttribute), true).Length > 0)
					{
						var descr = UserData.RegisterType(nestedType, this.AccessMode);

						if (descr != null)
							AddDynValue(nestedType.Name, UserData.CreateStatic(nestedType));
					}
				}
			}

			if (!membersToIgnore.Contains("[this]"))
			{
				if (Type.IsArray)
				{
					int rank = Type.GetArrayRank();

					ParameterDescriptor[] get_pars = new ParameterDescriptor[rank];
					ParameterDescriptor[] set_pars = new ParameterDescriptor[rank + 1];

					for (int i = 0; i < rank; i++)
						get_pars[i] = set_pars[i] = new ParameterDescriptor("idx" + i.ToString(), typeof(int));

					set_pars[rank] = new ParameterDescriptor("value", Type.GetElementType());

					AddMember(SPECIALNAME_INDEXER_SET, new ArrayMemberDescriptor(SPECIALNAME_INDEXER_SET, true, set_pars));
					AddMember(SPECIALNAME_INDEXER_GET, new ArrayMemberDescriptor(SPECIALNAME_INDEXER_GET, false, get_pars));
				}
				else if (Type == typeof(Array))
				{
					AddMember(SPECIALNAME_INDEXER_SET, new ArrayMemberDescriptor(SPECIALNAME_INDEXER_SET, true));
					AddMember(SPECIALNAME_INDEXER_GET, new ArrayMemberDescriptor(SPECIALNAME_INDEXER_GET, false));
				}
			}
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="ObjectCallbackMemberDescriptor"/> class.
		/// Members defined with this constructor will support overload resolution.
		/// </summary>
		/// <param name="funcName">Name of the function.</param>
		/// <param name="callBack">The call back.</param>
		/// <param name="parameters">The parameters.</param>
		public ObjectCallbackMemberDescriptor(string funcName, Func<object, ScriptExecutionContext, CallbackArguments, object> callBack, ParameterDescriptor[] parameters)
		{
			m_CallbackFunc = callBack;
			Initialize(funcName, false, parameters, false);
		}