BinderHelper
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Microsoft.CSharp.RuntimeBinder
{
internal static class BinderHelper
{
internal static DynamicMetaObject Bind(DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable<DynamicMetaObject> args, IEnumerable<CSharpArgumentInfo> arginfos, DynamicMetaObject onBindingError)
{
List<Expression> list = new List<Expression>();
BindingRestrictions bindingRestrictions = BindingRestrictions.Empty;
ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder;
ParameterExpression parameterExpression = null;
IEnumerator<CSharpArgumentInfo> enumerator = arginfos?.GetEnumerator();
int num = 0;
foreach (DynamicMetaObject arg in args) {
if (!arg.HasValue)
throw Error.InternalCompilerError();
CSharpArgumentInfo cSharpArgumentInfo = null;
if (enumerator != null && enumerator.MoveNext())
cSharpArgumentInfo = enumerator.Current;
if (num == 0 && IsIncrementOrDecrementActionOnLocal(action)) {
parameterExpression = Expression.Variable((arg.Value != null) ? arg.Value.GetType() : typeof(object), "t0");
list.Add(parameterExpression);
} else
list.Add(arg.Expression);
BindingRestrictions restrictions = DeduceArgumentRestriction(num, callPayload, arg, cSharpArgumentInfo);
bindingRestrictions = bindingRestrictions.Merge(restrictions);
if (cSharpArgumentInfo != null && cSharpArgumentInfo.LiteralConstant && (!(arg.Value is float) || !float.IsNaN((float)arg.Value)) && (!(arg.Value is double) || !double.IsNaN((double)arg.Value))) {
Expression expression = Expression.Equal(arg.Expression, Expression.Constant(arg.Value, arg.Expression.Type));
restrictions = BindingRestrictions.GetExpressionRestriction(expression);
bindingRestrictions = bindingRestrictions.Merge(restrictions);
}
num++;
}
try {
Expression expression2 = binder.Bind(action, list, args.ToArray(), out DynamicMetaObject deferredBinding);
if (deferredBinding == null) {
if (parameterExpression != null) {
DynamicMetaObject dynamicMetaObject = args.First();
Expression item = Expression.Assign(parameterExpression, Expression.Convert(dynamicMetaObject.Expression, dynamicMetaObject.Value.GetType()));
Expression item2 = Expression.Assign(dynamicMetaObject.Expression, Expression.Convert(parameterExpression, dynamicMetaObject.Expression.Type));
List<Expression> list2 = new List<Expression>();
list2.Add(item);
list2.Add(expression2);
list2.Add(item2);
expression2 = Expression.Block(new ParameterExpression[1] {
parameterExpression
}, list2);
}
expression2 = ConvertResult(expression2, action);
return new DynamicMetaObject(expression2, bindingRestrictions);
}
expression2 = ConvertResult(deferredBinding.Expression, action);
bindingRestrictions = deferredBinding.Restrictions.Merge(bindingRestrictions);
return new DynamicMetaObject(expression2, bindingRestrictions);
} catch (RuntimeBinderException ex) {
if (onBindingError == null)
return new DynamicMetaObject(Expression.Throw(Expression.New(typeof(RuntimeBinderException).GetConstructor(new Type[1] {
typeof(string)
}), Expression.Constant(ex.Message)), GetTypeForErrorMetaObject(action, args.FirstOrDefault())), bindingRestrictions);
return onBindingError;
}
}
private static bool IsTypeOfStaticCall(int parameterIndex, ICSharpInvokeOrInvokeMemberBinder callPayload)
{
if (parameterIndex == 0 && callPayload != null)
return callPayload.StaticCall;
return false;
}
private static bool IsComObject(object obj)
{
if (obj != null)
return Marshal.IsComObject(obj);
return false;
}
internal static bool IsWindowsRuntimeObject(DynamicMetaObject obj)
{
if (obj != null && (object)obj.RuntimeType != null) {
Type type = obj.RuntimeType;
while ((object)type != null) {
if ((type.GetTypeInfo().get_Attributes() & TypeAttributes.WindowsRuntime) == TypeAttributes.WindowsRuntime)
return true;
if ((type.GetTypeInfo().get_Attributes() & TypeAttributes.Import) == TypeAttributes.Import)
return false;
type = type.GetTypeInfo().get_BaseType();
}
}
return false;
}
private static bool IsTransparentProxy(object obj)
{
return false;
}
private static bool IsDynamicallyTypedRuntimeProxy(DynamicMetaObject argument, CSharpArgumentInfo info)
{
return info != null && !info.UseCompileTimeType && (IsComObject(argument.Value) || IsTransparentProxy(argument.Value));
}
private static BindingRestrictions DeduceArgumentRestriction(int parameterIndex, ICSharpInvokeOrInvokeMemberBinder callPayload, DynamicMetaObject argument, CSharpArgumentInfo info)
{
if (argument.Value != null && !IsTypeOfStaticCall(parameterIndex, callPayload) && !IsDynamicallyTypedRuntimeProxy(argument, info))
return BindingRestrictions.GetTypeRestriction(argument.Expression, argument.RuntimeType);
return BindingRestrictions.GetInstanceRestriction(argument.Expression, argument.Value);
}
private static Expression ConvertResult(Expression binding, DynamicMetaObjectBinder action)
{
CSharpInvokeConstructorBinder cSharpInvokeConstructorBinder = action as CSharpInvokeConstructorBinder;
if (cSharpInvokeConstructorBinder != null)
return binding;
if ((object)binding.Type == typeof(void)) {
ICSharpInvokeOrInvokeMemberBinder iCSharpInvokeOrInvokeMemberBinder = action as ICSharpInvokeOrInvokeMemberBinder;
if (iCSharpInvokeOrInvokeMemberBinder != null && iCSharpInvokeOrInvokeMemberBinder.ResultDiscarded)
return Expression.Block(binding, Expression.Default(action.ReturnType));
throw Error.BindToVoidMethodButExpectResult();
}
if (binding.Type.GetTypeInfo().get_IsValueType() && !action.ReturnType.GetTypeInfo().get_IsValueType())
return Expression.Convert(binding, action.ReturnType);
return binding;
}
private static Type GetTypeForErrorMetaObject(DynamicMetaObjectBinder action, DynamicMetaObject arg0)
{
CSharpInvokeConstructorBinder cSharpInvokeConstructorBinder = action as CSharpInvokeConstructorBinder;
if (cSharpInvokeConstructorBinder != null) {
if (arg0 == null || !(arg0.Value is Type))
return typeof(object);
return arg0.Value as Type;
}
return action.ReturnType;
}
private static bool IsIncrementOrDecrementActionOnLocal(DynamicMetaObjectBinder action)
{
CSharpUnaryOperationBinder cSharpUnaryOperationBinder = action as CSharpUnaryOperationBinder;
if (cSharpUnaryOperationBinder != null) {
if (cSharpUnaryOperationBinder.Operation != ExpressionType.Increment)
return cSharpUnaryOperationBinder.Operation == ExpressionType.Decrement;
return true;
}
return false;
}
internal static IEnumerable<T> Cons<T>(T sourceHead, IEnumerable<T> sourceTail)
{
yield return sourceHead;
if (sourceTail != null) {
foreach (T item in sourceTail) {
yield return item;
}
}
}
internal static IEnumerable<T> Cons<T>(T sourceHead, IEnumerable<T> sourceMiddle, T sourceLast)
{
yield return sourceHead;
if (sourceMiddle != null) {
foreach (T item in sourceMiddle) {
yield return item;
}
}
yield return sourceLast;
}
internal static List<T> ToList<T>(IEnumerable<T> source)
{
if (source == null)
return new List<T>();
return source.ToList();
}
internal static CallInfo CreateCallInfo(IEnumerable<CSharpArgumentInfo> argInfos, int discard)
{
int num = 0;
List<string> list = new List<string>();
foreach (CSharpArgumentInfo argInfo in argInfos) {
if (argInfo.NamedArgument)
list.Add(argInfo.Name);
num++;
}
return new CallInfo(num - discard, list);
}
}
}