diff --git a/ClearScript/HostItem.InvokeMethod.cs b/ClearScript/HostItem.InvokeMethod.cs index c6e74dea..9d8890ca 100644 --- a/ClearScript/HostItem.InvokeMethod.cs +++ b/ClearScript/HostItem.InvokeMethod.cs @@ -53,7 +53,7 @@ private object InvokeMethod(string name, object[] args, object[] bindArgs) private object InvokeMethod(string name, Type[] typeArgs, object[] args, object[] bindArgs) { var bindResult = BindMethod(name, typeArgs, args, bindArgs); - if ((bindResult is MethodBindFailure) && Target.GetFlags(this).HasFlag(HostTargetFlags.AllowExtensionMethods)) + if (!bindResult.IsSuccess && Target.GetFlags(this).HasFlag(HostTargetFlags.AllowExtensionMethods)) { var targetArg = Target.Target.ToEnumerable(); var extensionArgs = targetArg.Concat(args).ToArray(); @@ -65,7 +65,7 @@ private object InvokeMethod(string name, Type[] typeArgs, object[] args, object[ { var extensionHostItem = (HostItem)Wrap(Engine, HostType.Wrap(type)); var extensionBindResult = extensionHostItem.BindMethod(name, typeArgs, extensionArgs, extensionBindArgs); - if (extensionBindResult is MethodBindSuccess) + if (extensionBindResult.IsSuccess) { var result = extensionBindResult.Invoke(extensionHostItem); for (var index = 1; index < extensionArgs.Length; index++) @@ -121,16 +121,16 @@ private MethodBindResult BindMethod(string name, Type[] typeArgs, object[] args, if (forceReflection) { - result = new MethodBindFailure(() => new MissingMethodException(MiscHelpers.FormatInvariant("The object has no method named '{0}' that matches the specified arguments", name))); + result = new MethodBindResult(() => new MissingMethodException(MiscHelpers.FormatInvariant("The object has no method named '{0}' that matches the specified arguments", name))); } else { result = BindMethodInternal(signature, AccessContext, bindFlags, Target, name, typeArgs, args, bindArgs); if (!result.IsPreferredMethod(this, name)) { - if (result is MethodBindSuccess) + if (result.IsSuccess) { - result = new MethodBindFailure(() => new MissingMethodException(MiscHelpers.FormatInvariant("The object has no method named '{0}' that matches the specified arguments", name))); + result = new MethodBindResult(() => new MissingMethodException(MiscHelpers.FormatInvariant("The object has no method named '{0}' that matches the specified arguments", name))); } foreach (var altName in GetAltMethodNames(name, bindFlags)) @@ -145,10 +145,10 @@ private MethodBindResult BindMethod(string name, Type[] typeArgs, object[] args, } } - if ((result is MethodBindFailure) && (forceReflection || Engine.UseReflectionBindFallback)) + if ((!result.IsSuccess) && (forceReflection || Engine.UseReflectionBindFallback)) { var reflectionResult = BindMethodUsingReflection(bindFlags, Target, name, typeArgs, args, bindArgs); - if ((reflectionResult is MethodBindSuccess) || forceReflection) + if ((reflectionResult.IsSuccess) || forceReflection) { result = reflectionResult; } @@ -197,7 +197,7 @@ private static MethodBindResult BindMethodCore(Type bindContext, BindingFlags bi var rawResult = BindMethodRaw(bindFlags, binder, target, bindArgs); var result = MethodBindResult.Create(name, bindFlags, rawResult, target, args); - if ((result is MethodBindFailure) && !(target is HostType) && target.Type.IsInterface) + if (!result.IsSuccess && !(target is HostType) && target.Type.IsInterface) { // binding through interface failed; try base interfaces foreach (var interfaceType in target.Type.GetInterfaces()) @@ -206,7 +206,7 @@ private static MethodBindResult BindMethodCore(Type bindContext, BindingFlags bi rawResult = BindMethodRaw(bindFlags, binder, baseInterfaceTarget, bindArgs); var baseInterfaceResult = MethodBindResult.Create(name, bindFlags, rawResult, target, args); - if (baseInterfaceResult is MethodBindSuccess) + if (baseInterfaceResult.IsSuccess) { return baseInterfaceResult; } @@ -217,7 +217,7 @@ private static MethodBindResult BindMethodCore(Type bindContext, BindingFlags bi rawResult = BindMethodRaw(bindFlags, binder, objectTarget, bindArgs); var objectResult = MethodBindResult.Create(name, bindFlags, rawResult, target, args); - if (objectResult is MethodBindSuccess) + if (objectResult.IsSuccess) { return objectResult; } @@ -354,11 +354,11 @@ private MethodBindResult BindMethodUsingReflection(BindingFlags bindFlags, HostT } catch (AmbiguousMatchException) { - return new MethodBindFailure(() => new AmbiguousMatchException(MiscHelpers.FormatInvariant("The object has multiple methods named '{0}' that match the specified arguments", name))); + return new MethodBindResult(() => new AmbiguousMatchException(MiscHelpers.FormatInvariant("The object has multiple methods named '{0}' that match the specified arguments", name))); } } - return new MethodBindFailure(() => new MissingMethodException(MiscHelpers.FormatInvariant("The object has no method named '{0}' that matches the specified arguments", name))); + return new MethodBindResult(() => new MissingMethodException(MiscHelpers.FormatInvariant("The object has no method named '{0}' that matches the specified arguments", name))); } private IEnumerable GetReflectionCandidates(BindingFlags bindFlags, HostTarget hostTarget, string name, Type[] typeArgs) @@ -437,117 +437,80 @@ internal static long GetCoreBindCount() #region Nested type: MethodBindResult - private abstract class MethodBindResult - { - public static MethodBindResult Create(string name, BindingFlags bindFlags, object rawResult, HostTarget hostTarget, object[] args) - { - var method = rawResult as MethodInfo; - if (method != null) - { - if (method.IsStatic && !bindFlags.HasFlag(BindingFlags.Static)) - { - return new MethodBindFailure(() => new InvalidOperationException(MiscHelpers.FormatInvariant("Cannot access static method '{0}' in non-static context", method.Name))); - } - - return new MethodBindSuccess(hostTarget, method, args); - } - - return new MethodBindFailure((rawResult as Func) ?? (() => new NotSupportedException(MiscHelpers.FormatInvariant("Invocation of method '{0}' failed (unrecognized binding)", name)))); - } - - public abstract object RawResult { get; } - - public abstract bool IsPreferredMethod(HostItem hostItem, string name); - - public abstract bool IsUnblockedMethod(HostItem hostItem); - - public abstract object Invoke(HostItem hostItem); - } - - #endregion - - #region Nested type: MethodBindSuccess - - private sealed class MethodBindSuccess : MethodBindResult - { - private static readonly MethodInfo[] reflectionMethods = + private readonly ref struct MethodBindResult + { + private readonly HostTarget hostTarget; + private readonly MethodInfo method; + private readonly object[] args; + private readonly Func exceptionFactory; + + private static readonly MethodInfo[] reflectionMethods = { typeof(object).GetMethod("GetType"), typeof(System.Runtime.InteropServices._Exception).GetMethod("GetType"), typeof(Exception).GetMethod("GetType") - }; - - private readonly HostTarget hostTarget; - private readonly MethodInfo method; - private readonly object[] args; - - public MethodBindSuccess(HostTarget hostTarget, MethodInfo method, object[] args) + }; + + public MethodBindResult(HostTarget hostTarget, MethodInfo method, object[] args) { this.hostTarget = hostTarget; this.method = method; this.args = args; + exceptionFactory = null; + } + + public MethodBindResult(Func exceptionFactory) + { + hostTarget = null; + method = null; + args = null; + this.exceptionFactory = exceptionFactory; } - #region MethodBindResult overrides - - public override object RawResult => method; - - public override bool IsPreferredMethod(HostItem hostItem, string name) - { - return IsUnblockedMethod(hostItem) && (method.GetScriptName(hostItem) == name); - } - - public override bool IsUnblockedMethod(HostItem hostItem) - { - return !method.IsBlockedFromScript(hostItem, hostItem.DefaultAccess); - } - - public override object Invoke(HostItem hostItem) + public static MethodBindResult Create(string name, BindingFlags bindFlags, object rawResult, HostTarget hostTarget, object[] args) { - if (reflectionMethods.Contains(method, MemberComparer.Instance)) + var method = rawResult as MethodInfo; + if (method != null) { - hostItem.Engine.CheckReflection(); - } - - return InvokeHelpers.InvokeMethod(hostItem, method, hostTarget.InvokeTarget, args, method.GetScriptMemberFlags(hostItem)); - } - - #endregion - } + if (method.IsStatic && !bindFlags.HasFlag(BindingFlags.Static)) + { + return new MethodBindResult(() => new InvalidOperationException(MiscHelpers.FormatInvariant("Cannot access static method '{0}' in non-static context", method.Name))); + } - #endregion + return new MethodBindResult(hostTarget, method, args); + } - #region Nested type: MethodBindFailure + return new MethodBindResult((rawResult as Func) ?? (() => new NotSupportedException(MiscHelpers.FormatInvariant("Invocation of method '{0}' failed (unrecognized binding)", name)))); + } + + public bool IsSuccess => method != null; - private sealed class MethodBindFailure : MethodBindResult - { - private readonly Func exceptionFactory; + public object RawResult => IsSuccess ? (object)method : exceptionFactory; - public MethodBindFailure(Func exceptionFactory) - { - this.exceptionFactory = exceptionFactory; + public bool IsPreferredMethod(HostItem hostItem, string name) + { + return IsSuccess && IsUnblockedMethod(hostItem) && (method.GetScriptName(hostItem) == name); } - #region MethodBindResult overrides - - public override object RawResult => exceptionFactory; - - public override bool IsPreferredMethod(HostItem hostItem, string name) - { - return false; + public bool IsUnblockedMethod(HostItem hostItem) + { + return IsSuccess && !method.IsBlockedFromScript(hostItem, hostItem.DefaultAccess); } - public override bool IsUnblockedMethod(HostItem hostItem) - { - return false; - } + public object Invoke(HostItem hostItem) + { + if (!IsSuccess) + { + throw exceptionFactory(); + } + + if (reflectionMethods.Contains(method, MemberComparer.Instance)) + { + hostItem.Engine.CheckReflection(); + } - public override object Invoke(HostItem hostItem) - { - throw exceptionFactory(); + return InvokeHelpers.InvokeMethod(hostItem, method, hostTarget.InvokeTarget, args, method.GetScriptMemberFlags(hostItem)); } - - #endregion } #endregion