/// <summary> /// プロパティ名から値を高速取得する /// </summary> /// <param name="obj">取得対象のオブジェクト</param> /// <param name="propertyName">プロパティ名</param> /// <returns>プロパティの値</returns> public static object GetPropertyValue(this object obj, string propertyName) { var type = obj.GetType(); GetSiteCollection getSiteCollection = null; CallSite<Func<CallSite, object, object>> siteGet = null; //型キャッシュの存在確認 if (_getSiteCollectionCache.TryGetValue(type, out getSiteCollection)) { siteGet = getSiteCollection[propertyName]; //Getterキャッシュの存在確認 if (siteGet != null) { return siteGet.Target(siteGet, obj); } } var argInfo = new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }; siteGet = CallSite<Func<CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, propertyName, type, argInfo)); if (getSiteCollection == null) { getSiteCollection = new GetSiteCollection(propertyName, siteGet); _getSiteCollectionCache.Add(type, getSiteCollection); } else { getSiteCollection.Add(propertyName, siteGet); } return siteGet.Target(siteGet, obj); }
/// <summary> /// Reduces the dynamic expression to a binder and a set of arguments to apply the operation to. /// </summary> /// <param name="binder">The binder used to perform the dynamic operation.</param> /// <param name="arguments">The arguments to apply the dynamic operation to.</param> /// <param name="argumentTypes">The types of the arguments to use for the dynamic call site. Return null to infer types.</param> protected override void ReduceDynamic(out CallSiteBinder binder, out IEnumerable<Expression> arguments, out Type[] argumentTypes) { var n = Arguments.Count; var argumentInfos = new CSharpArgumentInfo[n + 1]; var expressions = new Expression[n + 1]; expressions[0] = Expression.Constant(Type, typeof(Type)); argumentInfos[0] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.IsStaticType, null); argumentTypes = null; CopyArguments(Arguments, argumentInfos, expressions, ref argumentTypes); binder = Binder.InvokeConstructor(Flags, Context, argumentInfos); arguments = expressions; }
/// <summary> /// Reduces the dynamic expression to a binder and a set of arguments to apply the operation to. /// </summary> /// <param name="binder">The binder used to perform the dynamic operation.</param> /// <param name="arguments">The arguments to apply the dynamic operation to.</param> /// <param name="argumentTypes">The types of the arguments to use for the dynamic call site. Return null to infer types.</param> protected override void ReduceDynamic(out CallSiteBinder binder, out IEnumerable<Expression> arguments, out Type[] argumentTypes) { var n = Arguments.Count; var argumentInfos = new CSharpArgumentInfo[n + 1]; var expressions = new Expression[n + 1]; expressions[0] = Expression; argumentInfos[0] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null); argumentTypes = null; CopyArguments(Arguments, argumentInfos, expressions, ref argumentTypes); binder = Binder.Invoke(Flags, Context, argumentInfos); arguments = expressions; }
/// <summary> /// Reduces the dynamic expression to a binder and a set of arguments to apply the operation to. /// </summary> /// <param name="binder">The binder used to perform the dynamic operation.</param> /// <param name="arguments">The arguments to apply the dynamic operation to.</param> /// <param name="argumentTypes">The types of the arguments to use for the dynamic call site. Return null to infer types.</param> protected override void ReduceDynamic(out CallSiteBinder binder, out IEnumerable<Expression> arguments, out Type[] argumentTypes) { var n = Arguments.Count; var argumentInfos = new CSharpArgumentInfo[n + 1]; var expressions = new Expression[n + 1]; // NB: By-ref passing for the receiver seems to be omitted in Roslyn here; see https://github.com/dotnet/roslyn/issues/6818. // We're choosing to be consistent with that behavior until further notice. expressions[0] = Object; argumentInfos[0] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null); argumentTypes = null; CopyArguments(Arguments, argumentInfos, expressions, ref argumentTypes); binder = Binder.GetIndex(Flags, Context, argumentInfos); arguments = expressions; }
// // Creates mcs expression from dynamic object // public Compiler.Expression CreateCompilerExpression (CSharpArgumentInfo info, DynamicMetaObject value) { // // No type details provider, go with runtime type // if (info == null) { if (value.LimitType == typeof (object)) return new Compiler.NullLiteral (Compiler.Location.Null); return new Compiler.RuntimeValueExpression (value, ImportType (value.RuntimeType)); } // // Value is known to be a type // if ((info.Flags & CSharpArgumentInfoFlags.IsStaticType) != 0) return new Compiler.TypeExpression (ImportType ((Type) value.Value), Compiler.Location.Null); if (value.Value == null && (info.Flags & (CSharpArgumentInfoFlags.IsOut | CSharpArgumentInfoFlags.IsRef | CSharpArgumentInfoFlags.UseCompileTimeType)) == 0 && value.LimitType == typeof (object)) { return new Compiler.NullLiteral (Compiler.Location.Null); } // // Use compilation time type when type was known not to be dynamic during compilation // Type value_type = (info.Flags & CSharpArgumentInfoFlags.UseCompileTimeType) != 0 ? value.Expression.Type : value.LimitType; var type = ImportType (value_type); if ((info.Flags & CSharpArgumentInfoFlags.Constant) != 0) return Compiler.Constant.CreateConstantFromValue (type, value.Value, Compiler.Location.Null); return new Compiler.RuntimeValueExpression (value, type); }
// // Creates mcs expression from dynamic method object // public static Compiler.Expression CreateCompilerExpression (CSharpArgumentInfo info, DynamicMetaObject value) { if (value.Value == null) { if (value.LimitType == typeof (object)) return new Compiler.NullLiteral (Compiler.Location.Null); InitializeCompiler (null); return Compiler.Constant.CreateConstantFromValue (TypeImporter.Import (value.LimitType), null, Compiler.Location.Null); } bool is_compile_time; if (info != null) { if ((info.Flags & CSharpArgumentInfoFlags.Constant) != 0) { InitializeCompiler (null); return Compiler.Constant.CreateConstantFromValue (TypeImporter.Import (value.LimitType), value.Value, Compiler.Location.Null); } if ((info.Flags & CSharpArgumentInfoFlags.IsStaticType) != 0) return new Compiler.TypeExpression (TypeImporter.Import ((Type) value.Value), Compiler.Location.Null); is_compile_time = (info.Flags & CSharpArgumentInfoFlags.UseCompileTimeType) != 0; } else { is_compile_time = false; } return new Compiler.RuntimeValueExpression (value, TypeImporter.Import (is_compile_time ? value.LimitType : value.RuntimeType)); }
public static void CopyArguments(ReadOnlyCollection<DynamicCSharpArgument> arguments, CSharpArgumentInfo[] argumentInfos, Expression[] expressions, ref Type[] argumentTypes) { var n = arguments.Count; for (var i = 0; i < n; i++) { var argument = arguments[i]; argumentInfos[i + 1] = argument.ArgumentInfo; expressions[i + 1] = argument.Expression; if ((argument.Flags & (CSharpArgumentInfoFlags.IsRef | CSharpArgumentInfoFlags.IsOut)) != 0) { if (argumentTypes == null) { argumentTypes = new Type[argumentInfos.Length]; argumentTypes[0] = expressions[0].Type; for (var j = 0; j < i; j++) { argumentTypes[j + 1] = arguments[j].Expression.Type; } } argumentTypes[i + 1] = argument.Expression.Type.MakeByRefType(); } else if (argumentTypes != null) { argumentTypes[i + 1] = argument.Expression.Type; } } }
public static void CopyReceiverArgument(Expression receiver, CSharpArgumentInfo[] argumentInfos, Expression[] expressions, ref Type[] argumentTypes) { var receiverFlags = CSharpArgumentInfoFlags.None; if (IsReceiverByRef(receiver)) { receiverFlags |= CSharpArgumentInfoFlags.IsRef; argumentTypes = new Type[argumentInfos.Length]; argumentTypes[0] = receiver.Type.MakeByRefType(); } expressions[0] = receiver; argumentInfos[0] = CSharpArgumentInfo.Create(receiverFlags, null); }
protected override void ReduceDynamic(out CallSiteBinder binder, out IEnumerable<Expression> arguments, out Type[] argumentTypes) { var n = Arguments.Count; var argumentInfos = new CSharpArgumentInfo[n + 1]; var expressions = new Expression[n + 1]; argumentTypes = null; CopyReceiverArgument(Object, argumentInfos, expressions, ref argumentTypes); CopyArguments(Arguments, argumentInfos, expressions, ref argumentTypes); binder = Binder.InvokeMember(Flags, Name, TypeArguments, Context, argumentInfos); arguments = expressions; }
private void ReduceAssignment(Expression value, CSharpBinderFlags flags, CSharpArgumentInfoFlags leftFlags, CSharpArgumentInfoFlags rightFlags, out CallSiteBinder binder, out IEnumerable<Expression> arguments, out Type[] argumentTypes) { var n = Arguments.Count; var argumentInfos = new CSharpArgumentInfo[n + 2]; var expressions = new Expression[n + 2]; // NB: By-ref passing for the receiver seems to be omitted in Roslyn here; see https://github.com/dotnet/roslyn/issues/6818. // We're choosing to be consistent with that behavior until further notice. expressions[0] = Object; argumentInfos[0] = CSharpArgumentInfo.Create(leftFlags, null); argumentTypes = null; CopyArguments(Arguments, argumentInfos, expressions, ref argumentTypes); argumentInfos[n + 1] = CSharpArgumentInfo.Create(rightFlags, null); // TODO: check expressions[n + 1] = value; flags |= Flags; binder = Binder.SetMember(flags, Name, Context, argumentInfos); arguments = expressions; }
///////////////////////////////////////////////////////////////////////////////// private static bool IsDynamicallyTypedRuntimeProxy(DynamicMetaObject argument, CSharpArgumentInfo info) { // This detects situations where, although the argument has a value with // a given type, that type is insufficient to determine, statically, the // set of reference conversions that are going to exist at bind time for // different values. For instance, one __ComObject may allow a conversion // to IFoo while another does not. bool isDynamicObject = info != null && !info.UseCompileTimeType && (IsComObject(argument.Value) || IsTransparentProxy(argument.Value)); return(isDynamicObject); }
internal static DynamicMetaObject Bind( DynamicMetaObjectBinder action, RuntimeBinder binder, DynamicMetaObject[] args, IEnumerable <CSharpArgumentInfo> arginfos, DynamicMetaObject onBindingError) { Expression[] parameters = new Expression[args.Length]; BindingRestrictions restrictions = BindingRestrictions.Empty; ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder; ParameterExpression tempForIncrement = null; IEnumerator <CSharpArgumentInfo> arginfosEnum = (arginfos ?? Array.Empty <CSharpArgumentInfo>()).GetEnumerator(); for (int index = 0; index < args.Length; ++index) { DynamicMetaObject o = args[index]; // Our contract with the DLR is such that we will not enter a bind unless we have // values for the meta-objects involved. if (!o.HasValue) { Debug.Assert(false, "The runtime binder is being asked to bind a metaobject without a value"); throw Error.InternalCompilerError(); } CSharpArgumentInfo info = arginfosEnum.MoveNext() ? arginfosEnum.Current : null; if (index == 0 && IsIncrementOrDecrementActionOnLocal(action)) { // We have an inc or a dec operation. Insert the temp local instead. // // We need to do this because for value types, the object will come // in boxed, and we'd need to unbox it to get the original type in order // to increment. The only way to do that is to create a new temporary. object value = o.Value; tempForIncrement = Expression.Variable(value != null ? value.GetType() : typeof(object), "t0"); parameters[0] = tempForIncrement; } else { parameters[index] = o.Expression; } BindingRestrictions r = DeduceArgumentRestriction(index, callPayload, o, info); restrictions = restrictions.Merge(r); // Here we check the argument info. If the argument info shows that the current argument // is a literal constant, then we also add an instance restriction on the value of // the constant. if (info != null && info.LiteralConstant) { if (o.Value is double && double.IsNaN((double)o.Value)) { MethodInfo isNaN = s_DoubleIsNaN ?? (s_DoubleIsNaN = typeof(double).GetMethod("IsNaN")); Expression e = Expression.Call(null, isNaN, o.Expression); restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(e)); } else if (o.Value is float && float.IsNaN((float)o.Value)) { MethodInfo isNaN = s_SingleIsNaN ?? (s_SingleIsNaN = typeof(float).GetMethod("IsNaN")); Expression e = Expression.Call(null, isNaN, o.Expression); restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(e)); } else { Expression e = Expression.Equal(o.Expression, Expression.Constant(o.Value, o.Expression.Type)); r = BindingRestrictions.GetExpressionRestriction(e); restrictions = restrictions.Merge(r); } } } // Get the bound expression. try { DynamicMetaObject deferredBinding; Expression expression = binder.Bind(action, parameters, args, out deferredBinding); if (deferredBinding != null) { expression = ConvertResult(deferredBinding.Expression, action); restrictions = deferredBinding.Restrictions.Merge(restrictions); return(new DynamicMetaObject(expression, restrictions)); } if (tempForIncrement != null) { // If we have a ++ or -- payload, we need to do some temp rewriting. // We rewrite to the following: // // temp = (type)o; // temp++; // o = temp; // return o; DynamicMetaObject arg0 = args[0]; expression = Expression.Block( new[] { tempForIncrement }, Expression.Assign(tempForIncrement, Expression.Convert(arg0.Expression, arg0.Value.GetType())), expression, Expression.Assign(arg0.Expression, Expression.Convert(tempForIncrement, arg0.Expression.Type))); } expression = ConvertResult(expression, action); return(new DynamicMetaObject(expression, restrictions)); } catch (RuntimeBinderException e) { if (onBindingError != null) { return(onBindingError); } return(new DynamicMetaObject( Expression.Throw( Expression.New( typeof(RuntimeBinderException).GetConstructor(new Type[] { typeof(string) }), Expression.Constant(e.Message) ), GetTypeForErrorMetaObject(action, args.Length == 0 ? null : args[0]) ), restrictions )); } }
internal static DynamicMetaObject Bind( DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable <DynamicMetaObject> args, IEnumerable <CSharpArgumentInfo> arginfos, DynamicMetaObject onBindingError) { List <Expression> parameters = new List <Expression>(); BindingRestrictions restrictions = BindingRestrictions.Empty; ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder; ParameterExpression tempForIncrement = null; IEnumerator <CSharpArgumentInfo> arginfosEnum = arginfos == null ? null : arginfos.GetEnumerator(); int index = 0; foreach (DynamicMetaObject o in args) { // Our contract with the DLR is such that we will not enter a bind unless we have // values for the meta-objects involved. if (!o.HasValue) { Debug.Assert(false, "The runtime binder is being asked to bind a metaobject without a value"); throw Error.InternalCompilerError(); } CSharpArgumentInfo info = null; if (arginfosEnum != null && arginfosEnum.MoveNext()) { info = arginfosEnum.Current; } if (index == 0 && IsIncrementOrDecrementActionOnLocal(action)) { // We have an inc or a dec operation. Insert the temp local instead. // // We need to do this because for value types, the object will come // in boxed, and we'd need to unbox it to get the original type in order // to increment. The only way to do that is to create a new temporary. tempForIncrement = Expression.Variable(o.Value != null ? o.Value.GetType() : typeof(object), "t0"); parameters.Add(tempForIncrement); } else { parameters.Add(o.Expression); } BindingRestrictions r = DeduceArgumentRestriction(index, callPayload, o, info); restrictions = restrictions.Merge(r); // Here we check the argument info. If the argument info shows that the current argument // is a literal constant, then we also add an instance restriction on the value of // the constant. if (info != null && info.LiteralConstant) { if ((o.Value is float && float.IsNaN((float)o.Value)) || o.Value is double && double.IsNaN((double)o.Value)) { // We cannot create an equality restriction for NaN, because equality is implemented // in such a way that NaN != NaN and the rule we make would be unsatisfiable. } else { Expression e = Expression.Equal(o.Expression, Expression.Constant(o.Value, o.Expression.Type)); r = BindingRestrictions.GetExpressionRestriction(e); restrictions = restrictions.Merge(r); } } ++index; } // Get the bound expression. try { DynamicMetaObject deferredBinding; Expression expression = binder.Bind(action, parameters, args.ToArray(), out deferredBinding); if (deferredBinding != null) { expression = ConvertResult(deferredBinding.Expression, action); restrictions = deferredBinding.Restrictions.Merge(restrictions); return(new DynamicMetaObject(expression, restrictions)); } if (tempForIncrement != null) { // If we have a ++ or -- payload, we need to do some temp rewriting. // We rewrite to the following: // // temp = (type)o; // temp++; // o = temp; // return o; DynamicMetaObject arg0 = Enumerable.First(args); Expression assignTemp = Expression.Assign( tempForIncrement, Expression.Convert(arg0.Expression, arg0.Value.GetType())); Expression assignResult = Expression.Assign( arg0.Expression, Expression.Convert(tempForIncrement, arg0.Expression.Type)); List <Expression> expressions = new List <Expression>(); expressions.Add(assignTemp); expressions.Add(expression); expressions.Add(assignResult); expression = Expression.Block(new ParameterExpression[] { tempForIncrement }, expressions); } expression = ConvertResult(expression, action); return(new DynamicMetaObject(expression, restrictions)); } catch (RuntimeBinderException e) { if (onBindingError != null) { return(onBindingError); } return(new DynamicMetaObject( Expression.Throw( Expression.New( typeof(RuntimeBinderException).GetConstructor(new Type[] { typeof(string) }), Expression.Constant(e.Message) ), GetTypeForErrorMetaObject(action, args.FirstOrDefault()) ), restrictions )); } }
private void ReduceAssignment(Expression value, CSharpBinderFlags flags, CSharpArgumentInfoFlags leftFlags, CSharpArgumentInfoFlags rightFlags, out CallSiteBinder binder, out IEnumerable<Expression> arguments, out Type[] argumentTypes) { var n = Arguments.Count; var argumentInfos = new CSharpArgumentInfo[n + 2]; var expressions = new Expression[n + 2]; // NB: This is the only place where by-ref passing for the receiver is done in Roslyn; for more // info about the apparent inconsistency see https://github.com/dotnet/roslyn/issues/6818. // We're choosing to be consistent with that behavior until further notice. if (IsReceiverByRef(Object)) { leftFlags |= CSharpArgumentInfoFlags.IsRef; } expressions[0] = Object; argumentInfos[0] = CSharpArgumentInfo.Create(leftFlags, null); argumentTypes = null; CopyArguments(Arguments, argumentInfos, expressions, ref argumentTypes); argumentInfos[n + 1] = CSharpArgumentInfo.Create(rightFlags, null); // TODO: check expressions[n + 1] = value; flags |= Flags; binder = Binder.SetIndex(flags, Context, argumentInfos); arguments = expressions; }
private static IEnumerable<CSharpArgumentInfo> GetBinderArguments(int count) { var arr = new CSharpArgumentInfo[count]; for (int i = 0; i < count; i++) { arr[i] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null); } return arr; }
// // Creates mcs expression from dynamic method object // public static Compiler.Expression CreateCompilerExpression (CSharpArgumentInfo info, DynamicMetaObject value, bool typed) { if (info.IsNamed) throw new NotImplementedException ("IsNamed"); if (value.Value == null) return new Compiler.NullLiteral (value.LimitType, Compiler.Location.Null); if ((info.Flags & CSharpArgumentInfoFlags.LiteralConstant) != 0) { if (!typed) throw new NotImplementedException ("weakly typed constant"); return Compiler.Constant.CreateConstant (value.RuntimeType ?? value.LimitType, value.Value, Compiler.Location.Null); } return new Compiler.RuntimeValueExpression (value, typed); }
private bool DeferBinding( DynamicMetaObjectBinder payload, ArgumentObject[] arguments, DynamicMetaObject[] args, Dictionary<int, LocalVariableSymbol> dictionary, out DynamicMetaObject deferredBinding) { // This method deals with any deferrals we need to do. We check deferrals up front // and bail early if we need to do them. // (1) InvokeMember deferral. // // This is the deferral for the d.Foo() scenario where Foo actually binds to a // field or property, and not a method group that is invocable. We defer to // the standard GetMember/Invoke pattern. if (payload is CSharpInvokeMemberBinder) { ICSharpInvokeOrInvokeMemberBinder callPayload = payload as ICSharpInvokeOrInvokeMemberBinder; int arity = callPayload.TypeArguments != null ? callPayload.TypeArguments.Count : 0; MemberLookup mem = new MemberLookup(); EXPR callingObject = CreateCallingObjectForCall(callPayload, arguments, dictionary); Debug.Assert(_bindingContext.ContextForMemberLookup() != null); SymWithType swt = _symbolTable.LookupMember( callPayload.Name, callingObject, _bindingContext.ContextForMemberLookup(), arity, mem, (callPayload.Flags & CSharpCallFlags.EventHookup) != 0, true); if (swt != null && swt.Sym.getKind() != SYMKIND.SK_MethodSymbol) { // The GetMember only has one argument, and we need to just take the first arg info. CSharpGetMemberBinder getMember = new CSharpGetMemberBinder(callPayload.Name, false, callPayload.CallingContext, new CSharpArgumentInfo[] { callPayload.ArgumentInfo[0] }); // The Invoke has the remaining argument infos. However, we need to redo the first one // to correspond to the GetMember result. CSharpArgumentInfo[] argInfos = new CSharpArgumentInfo[callPayload.ArgumentInfo.Count]; callPayload.ArgumentInfo.CopyTo(argInfos, 0); argInfos[0] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null); CSharpInvokeBinder invoke = new CSharpInvokeBinder(callPayload.Flags, callPayload.CallingContext, argInfos); DynamicMetaObject[] newArgs = new DynamicMetaObject[args.Length - 1]; Array.Copy(args, 1, newArgs, 0, args.Length - 1); deferredBinding = invoke.Defer(getMember.Defer(args[0]), newArgs); return true; } } deferredBinding = null; return false; }
public static object TryEvalUnaryOperators <T>(T obj, ExpressionType oper, Type accessibilityContext) { if (oper == ExpressionType.IsTrue || oper == ExpressionType.IsFalse) { var trueFalseSite = CallSite <Func <CallSite, T, bool> > .Create(new Microsoft.CSharp.RuntimeBinder.CSharpUnaryOperationBinder(oper, false, accessibilityContext, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) })); return(trueFalseSite.Target(trueFalseSite, obj)); } var site = CallSite <Func <CallSite, T, object> > .Create(new Microsoft.CSharp.RuntimeBinder.CSharpUnaryOperationBinder(oper, false, accessibilityContext, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) })); return(site.Target(site, obj)); }