/* **************************************************************************** * * Copyright (c) Microsoft Corporation. * * This source code is subject to terms and conditions of the Microsoft Public License. A * copy of the license can be found in the License.html file at the root of this distribution. If * you cannot locate the Microsoft Public License, please send an email to * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound * by the terms of the Microsoft Public License. * * You must not remove this notice, or any other, from this software. * * * ***************************************************************************/ using System; using Microsoft; #if !SILVERLIGHT using System.Collections.ObjectModel; using System.Diagnostics; #if CODEPLEX_40 using System.Linq.Expressions; #else using Microsoft.Linq.Expressions; #endif using System.Runtime.CompilerServices; #if !CODEPLEX_40 using Microsoft.Runtime.CompilerServices; #endif #if CODEPLEX_40 namespace System.Dynamic { #else namespace Microsoft.Scripting { #endif /// /// Invokes the object. If it falls back, just produce an error. /// internal sealed class ComInvokeAction : InvokeBinder { internal ComInvokeAction(CallInfo callInfo) : base(callInfo) { } public override int GetHashCode() { return base.GetHashCode(); } public override bool Equals(object obj) { return base.Equals(obj as ComInvokeAction); } public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) { return errorSuggestion ?? new DynamicMetaObject( Expression.Throw( Expression.New( typeof(NotSupportedException).GetConstructor(new[] { typeof(string) }), Expression.Constant(Strings.CannotCall) ) ), target.Restrictions.Merge(BindingRestrictions.Combine(args)) ); } } /// /// Splats the arguments to another nested dynamic site, which does the /// real invocation of the IDynamicMetaObjectProvider. /// internal sealed class SplatInvokeBinder : CallSiteBinder { internal readonly static SplatInvokeBinder Instance = new SplatInvokeBinder(); // Just splat the args and dispatch through a nested site public override Expression Bind(object[] args, ReadOnlyCollection parameters, LabelTarget returnLabel) { Debug.Assert(args.Length == 2); int count = ((object[])args[1]).Length; ParameterExpression array = parameters[1]; var nestedArgs = new ReadOnlyCollectionBuilder(count + 1); var delegateArgs = new Type[count + 3]; // args + target + returnType + CallSite nestedArgs.Add(parameters[0]); delegateArgs[0] = typeof(CallSite); delegateArgs[1] = typeof(object); for (int i = 0; i < count; i++) { nestedArgs.Add(Expression.ArrayAccess(array, Expression.Constant(i))); delegateArgs[i + 2] = typeof(object).MakeByRefType(); } delegateArgs[delegateArgs.Length - 1] = typeof(object); return Expression.IfThen( Expression.Equal(Expression.ArrayLength(array), Expression.Constant(count)), Expression.Return( returnLabel, Expression.MakeDynamic( Expression.GetDelegateType(delegateArgs), new ComInvokeAction(new CallInfo(count)), nestedArgs ) ) ); } } } #endif