public void TypeSubstitutionExpressionVisitor_NewArrayInit_Simple() { var subst = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> { { typeof(string), typeof(bool) } }); var expA = Expression.NewArrayInit(typeof(string), Expression.Parameter(typeof(string), "e1"), Expression.Parameter(typeof(string), "e2")); var expB = Expression.NewArrayInit(typeof(int), Expression.Parameter(typeof(int), "e1"), Expression.Parameter(typeof(int), "e2")); var res1 = subst.Apply(expA); var res2 = subst.Apply(expB); AssertEqual(res1, Expression.NewArrayInit(typeof(bool), Expression.Parameter(typeof(bool), "e1"), Expression.Parameter(typeof(bool), "e2"))); Assert.AreSame(expB, res2); }
public void TypeSubstitutionExpressionVisitor_NewArrayBounds_Simple() { var subst = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> { { typeof(string), typeof(bool) } }); var expA = Expression.NewArrayBounds(typeof(string), Expression.Constant(1)); var expB = Expression.NewArrayBounds(typeof(int), Expression.Constant(1)); var res1 = subst.Apply(expA); var res2 = subst.Apply(expB); AssertEqual(res1, Expression.NewArrayBounds(typeof(bool), Expression.Constant(1))); Assert.AreSame(expB, res2); }
/// <summary> /// Casts expressions containing reactive interface types to metadata entity types. /// </summary> /// <param name="expression">The expression to replace types in.</param> /// <returns>The expression with interface types replaced by metadata entity types.</returns> private static Expression CastExpression(Expression expression) { var subst = new TypeSubstitutionExpressionVisitor(new Dictionary<Type, Type> { { typeof(TMetadataInterface), typeof(TMetadataEntity) }, }); var result = subst.Apply(expression); return result; }
public void TypeSubstitutionExpressionVisitor_Anonymize() { var pers = typeof(Person); var query = (Expression <Func <IEnumerable <Person>, IEnumerable <string> > >)(xs => from x in xs where x.Age > 10 let name = x.Name where name.StartsWith("B") select name.ToUpper() + " is " + x.Age); var check1 = new TypeErasureChecker(new[] { typeof(Person) }); Assert.ThrowsException <InvalidOperationException>(() => check1.Visit(query)); var anon = RuntimeCompiler.CreateAnonymousType(new[] { new KeyValuePair <string, Type>("Name", typeof(string)), new KeyValuePair <string, Type>("Age", typeof(int)), }); var subst1 = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> { { pers, anon } }); var res1 = subst1.Apply(query); check1.Visit(res1); var check2 = new TypeErasureChecker(new[] { anon }); Assert.ThrowsException <InvalidOperationException>(() => check2.Visit(res1)); var f = ((LambdaExpression)res1).Compile(); var cast = ((MethodInfo)ReflectionHelpers.InfoOf(() => Enumerable.Cast <int>(null))).GetGenericMethodDefinition().MakeGenericMethod(anon); var peopleObj = new[] { Activator.CreateInstance(anon, new object[] { "Bart", 10 }), Activator.CreateInstance(anon, new object[] { "Lisa", 8 }), Activator.CreateInstance(anon, new object[] { "Bart", 21 }) }; var peopleAnon = cast.Invoke(obj: null, new object[] { peopleObj }); var qres = (IEnumerable <string>)f.DynamicInvoke(peopleAnon); Assert.IsTrue(new[] { "BART is 21" }.SequenceEqual(qres)); var subst2 = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> { { anon, pers } }); var res2 = subst2.Apply(res1); check2.Visit(res2); Assert.ThrowsException <InvalidOperationException>(() => check1.Visit(res2)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(query, res2)); }
public void TypeSubstitutionExpressionVisitor_ConstantChange_Fail() { Expression <Func <int> > f = () => 42; var subst = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> { { typeof(int), typeof(long) } }); Assert.ThrowsException <InvalidOperationException>(() => subst.Apply(f)); }
/// <summary> /// Rewrites a stream to an untyped stream if the stream definition /// is closed over wildcard types, and the stream factory returns /// an untyped stream. /// </summary> /// <param name="key">The stream identifier.</param> /// <param name="expr">The stream expression.</param> /// <returns> /// The stream expression with types rewritten to the untyped stream /// variant if the expression meets the expected criteria. /// </returns> private Expression RewriteQuotedReactiveStreamToUntyped(string key, Expression expr) { // Search for free variables var freeVariables = FreeVariableScanner.Scan(expr).ToArray(); // For now, with the absence of stream factory operators, it is safe to // throw if there is more than one free variable as all stream expressions // will be invocations of exactly one unbound stream factory parameter. if (freeVariables.Length > 1) { throw new InvalidOperationException( string.Format(CultureInfo.InvariantCulture, "Unexpected stream expression '{0}' for key '{1}' on query engine '{2}'.", expr.ToTraceString(), key, _queryEngine.Uri.ToCanonicalString())); } if (freeVariables.Length == 1) { // Find single stream factory parameter expression var streamFactoryParam = freeVariables[0]; if (streamFactoryParam != null) { // Resolve stream factory type from metadata if (_queryEngine._registry.SubjectFactories.TryGetValue(streamFactoryParam.Name, out var streamFactoryDefinition)) { // TODO: support rewrites based on stream factory classes // If definition is a lambda expression, rewrite to the return type var streamFactoryType = streamFactoryDefinition.Expression.Type; var invokeMethod = streamFactoryType.GetMethod("Invoke"); if (invokeMethod != null && invokeMethod.ReturnType == typeof(IMultiSubject)) { var actualStreamType = expr.Type; var expectedStreamType = invokeMethod.ReturnType; if (actualStreamType != expectedStreamType) { var substitutionVisitor = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> { { actualStreamType, expectedStreamType } }); _queryEngine.TraceSource.LazyStream_TypeRewrite(key, actualStreamType, expectedStreamType, _queryEngine.Uri); return(substitutionVisitor.Apply(expr)); } } } } } return(expr); }