BinderHelper
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Numerics.Hashing;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Microsoft.CSharp.RuntimeBinder
{
internal static class BinderHelper
{
private static MethodInfo s_DoubleIsNaN;
private static MethodInfo s_SingleIsNaN;
internal static DynamicMetaObject Bind(ICSharpBinder action, RuntimeBinder binder, DynamicMetaObject[] args, IEnumerable<CSharpArgumentInfo> arginfos, DynamicMetaObject onBindingError)
{
Expression[] array = new Expression[args.Length];
BindingRestrictions bindingRestrictions = BindingRestrictions.Empty;
ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder;
ParameterExpression parameterExpression = null;
IEnumerator<CSharpArgumentInfo> enumerator = (arginfos ?? Array.Empty<CSharpArgumentInfo>()).GetEnumerator();
for (int i = 0; i < args.Length; i++) {
DynamicMetaObject dynamicMetaObject = args[i];
CSharpArgumentInfo cSharpArgumentInfo = enumerator.MoveNext() ? enumerator.Current : null;
if (i == 0 && IsIncrementOrDecrementActionOnLocal(action)) {
object value = dynamicMetaObject.Value;
parameterExpression = (ParameterExpression)(array[0] = Expression.Variable((value != null) ? value.GetType() : typeof(object), "t0"));
} else
array[i] = dynamicMetaObject.Expression;
BindingRestrictions restrictions = DeduceArgumentRestriction(i, callPayload, dynamicMetaObject, cSharpArgumentInfo);
bindingRestrictions = bindingRestrictions.Merge(restrictions);
if (cSharpArgumentInfo != null && cSharpArgumentInfo.LiteralConstant) {
if (dynamicMetaObject.Value is double && double.IsNaN((double)dynamicMetaObject.Value)) {
MethodInfo method = s_DoubleIsNaN ?? (s_DoubleIsNaN = typeof(double).GetMethod("IsNaN"));
Expression expression = Expression.Call(null, method, dynamicMetaObject.Expression);
bindingRestrictions = bindingRestrictions.Merge(BindingRestrictions.GetExpressionRestriction(expression));
} else if (dynamicMetaObject.Value is float && float.IsNaN((float)dynamicMetaObject.Value)) {
MethodInfo method2 = s_SingleIsNaN ?? (s_SingleIsNaN = typeof(float).GetMethod("IsNaN"));
Expression expression2 = Expression.Call(null, method2, dynamicMetaObject.Expression);
bindingRestrictions = bindingRestrictions.Merge(BindingRestrictions.GetExpressionRestriction(expression2));
} else {
Expression expression3 = Expression.Equal(dynamicMetaObject.Expression, Expression.Constant(dynamicMetaObject.Value, dynamicMetaObject.Expression.Type));
restrictions = BindingRestrictions.GetExpressionRestriction(expression3);
bindingRestrictions = bindingRestrictions.Merge(restrictions);
}
}
}
try {
Expression expression4 = binder.Bind(action, array, args, out DynamicMetaObject deferredBinding);
if (deferredBinding == null) {
if (parameterExpression != null) {
DynamicMetaObject dynamicMetaObject2 = args[0];
expression4 = Expression.Block(new ParameterExpression[1] {
parameterExpression
}, Expression.Assign(parameterExpression, Expression.Convert(dynamicMetaObject2.Expression, dynamicMetaObject2.Value.GetType())), expression4, Expression.Assign(dynamicMetaObject2.Expression, Expression.Convert(parameterExpression, dynamicMetaObject2.Expression.Type)));
}
expression4 = ConvertResult(expression4, action);
return new DynamicMetaObject(expression4, bindingRestrictions);
}
expression4 = ConvertResult(deferredBinding.Expression, action);
bindingRestrictions = deferredBinding.Restrictions.Merge(bindingRestrictions);
return new DynamicMetaObject(expression4, 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)), bindingRestrictions);
return onBindingError;
}
}
public static void ValidateBindArgument(DynamicMetaObject argument, string paramName)
{
if (argument == null)
throw Error.ArgumentNull(paramName);
if (!argument.HasValue)
throw Error.DynamicArgumentNeedsValue(paramName);
}
public static void ValidateBindArgument(DynamicMetaObject[] arguments, string paramName)
{
if (arguments != null) {
for (int i = 0; i != arguments.Length; i++) {
ValidateBindArgument(arguments[i], $"{paramName}""{i}""");
}
}
}
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;
}
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, ICSharpBinder action)
{
if (action is CSharpInvokeConstructorBinder)
return binding;
if (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.IsValueType && !action.ReturnType.IsValueType)
return Expression.Convert(binding, action.ReturnType);
return binding;
}
private static Type GetTypeForErrorMetaObject(ICSharpBinder action, DynamicMetaObject[] args)
{
if (action is CSharpInvokeConstructorBinder)
return args[0].Value as Type;
return action.ReturnType;
}
private static bool IsIncrementOrDecrementActionOnLocal(ICSharpBinder 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 T[] Cons<T>(T sourceHead, T[] sourceTail)
{
if (sourceTail == null || sourceTail.Length != 0) {
T[] array = new T[sourceTail.Length + 1];
array[0] = sourceHead;
sourceTail.CopyTo(array, 1);
return array;
}
return new T[1] {
sourceHead
};
}
internal static T[] Cons<T>(T sourceHead, T[] sourceMiddle, T sourceLast)
{
if (sourceMiddle == null || sourceMiddle.Length != 0) {
T[] array = new T[sourceMiddle.Length + 2];
array[0] = sourceHead;
array[array.Length - 1] = sourceLast;
sourceMiddle.CopyTo(array, 1);
return array;
}
return new T[2] {
sourceHead,
sourceLast
};
}
internal static T[] ToArray<T>(IEnumerable<T> source)
{
if (source != null)
return source.ToArray();
return Array.Empty<T>();
}
internal static CallInfo CreateCallInfo(ref IEnumerable<CSharpArgumentInfo> argInfos, int discard)
{
int num = 0;
List<string> list = new List<string>();
CSharpArgumentInfo[] array = (CSharpArgumentInfo[])(argInfos = ToArray(argInfos));
foreach (CSharpArgumentInfo cSharpArgumentInfo in array) {
if (cSharpArgumentInfo.NamedArgument)
list.Add(cSharpArgumentInfo.Name);
num++;
}
return new CallInfo(num - discard, list);
}
internal static string GetCLROperatorName(this ExpressionType p)
{
switch (p) {
default:
return null;
case ExpressionType.Add:
return "op_Addition";
case ExpressionType.Subtract:
return "op_Subtraction";
case ExpressionType.Multiply:
return "op_Multiply";
case ExpressionType.Divide:
return "op_Division";
case ExpressionType.Modulo:
return "op_Modulus";
case ExpressionType.LeftShift:
return "op_LeftShift";
case ExpressionType.RightShift:
return "op_RightShift";
case ExpressionType.LessThan:
return "op_LessThan";
case ExpressionType.GreaterThan:
return "op_GreaterThan";
case ExpressionType.LessThanOrEqual:
return "op_LessThanOrEqual";
case ExpressionType.GreaterThanOrEqual:
return "op_GreaterThanOrEqual";
case ExpressionType.Equal:
return "op_Equality";
case ExpressionType.NotEqual:
return "op_Inequality";
case ExpressionType.And:
return "op_BitwiseAnd";
case ExpressionType.ExclusiveOr:
return "op_ExclusiveOr";
case ExpressionType.Or:
return "op_BitwiseOr";
case ExpressionType.AddAssign:
return "op_Addition";
case ExpressionType.SubtractAssign:
return "op_Subtraction";
case ExpressionType.MultiplyAssign:
return "op_Multiply";
case ExpressionType.DivideAssign:
return "op_Division";
case ExpressionType.ModuloAssign:
return "op_Modulus";
case ExpressionType.AndAssign:
return "op_BitwiseAnd";
case ExpressionType.ExclusiveOrAssign:
return "op_ExclusiveOr";
case ExpressionType.OrAssign:
return "op_BitwiseOr";
case ExpressionType.LeftShiftAssign:
return "op_LeftShift";
case ExpressionType.RightShiftAssign:
return "op_RightShift";
case ExpressionType.Negate:
return "op_UnaryNegation";
case ExpressionType.UnaryPlus:
return "op_UnaryPlus";
case ExpressionType.Not:
return "op_LogicalNot";
case ExpressionType.OnesComplement:
return "op_OnesComplement";
case ExpressionType.IsTrue:
return "op_True";
case ExpressionType.IsFalse:
return "op_False";
case ExpressionType.Increment:
return "op_Increment";
case ExpressionType.Decrement:
return "op_Decrement";
}
}
internal static int AddArgHashes(int hash, Type[] typeArguments, CSharpArgumentInfo[] argInfos)
{
foreach (Type type in typeArguments) {
hash = HashHelpers.Combine(hash, type.GetHashCode());
}
return AddArgHashes(hash, argInfos);
}
internal static int AddArgHashes(int hash, CSharpArgumentInfo[] argInfos)
{
foreach (CSharpArgumentInfo cSharpArgumentInfo in argInfos) {
hash = HashHelpers.Combine(hash, (int)cSharpArgumentInfo.Flags);
string name = cSharpArgumentInfo.Name;
if (!string.IsNullOrEmpty(name))
hash = HashHelpers.Combine(hash, name.GetHashCode());
}
return hash;
}
internal static bool CompareArgInfos(Type[] typeArgs, Type[] otherTypeArgs, CSharpArgumentInfo[] argInfos, CSharpArgumentInfo[] otherArgInfos)
{
for (int i = 0; i < typeArgs.Length; i++) {
if (typeArgs[i] != otherTypeArgs[i])
return false;
}
return CompareArgInfos(argInfos, otherArgInfos);
}
internal static bool CompareArgInfos(CSharpArgumentInfo[] argInfos, CSharpArgumentInfo[] otherArgInfos)
{
for (int i = 0; i < argInfos.Length; i++) {
CSharpArgumentInfo cSharpArgumentInfo = argInfos[i];
CSharpArgumentInfo cSharpArgumentInfo2 = otherArgInfos[i];
if (cSharpArgumentInfo.Flags != cSharpArgumentInfo2.Flags || cSharpArgumentInfo.Name != cSharpArgumentInfo2.Name)
return false;
}
return true;
}
}
}