Strongly-typed and parameterized exception factory.
コード例 #1
0
        public static ConditionalArrayIndexCSharpExpression ConditionalArrayIndex(Expression array, IEnumerable <Expression> indexes)
        {
            RequiresCanRead(array, nameof(array));
            ContractUtils.RequiresNotNull(indexes, nameof(indexes));

            if (!array.Type.IsArray)
            {
                throw LinqError.ArgumentMustBeArray();
            }

            var indexList = indexes.ToReadOnly();

            if (array.Type.GetArrayRank() != indexList.Count)
            {
                throw LinqError.IncorrectNumberOfIndexes();
            }

            foreach (var index in indexList)
            {
                RequiresCanRead(index, "indexes");

                if (index.Type != typeof(int))
                {
                    throw LinqError.ArgumentMustBeArrayIndexType();
                }
            }

            return(new ConditionalArrayIndexCSharpExpression(array, indexList));
        }
コード例 #2
0
        /// <summary>
        /// Creates a <see cref="ForCSharpStatement"/> that represents a for loop.
        /// </summary>
        /// <param name="initializers">The loop initializers.</param>
        /// <param name="test">The condition of the loop.</param>
        /// <param name="iterators">The loop iterators.</param>
        /// <param name="body">The body of the loop.</param>
        /// <param name="break">The break target used by the loop body.</param>
        /// <param name="continue">The continue target used by the loop body.</param>
        /// <returns>The created <see cref="ForCSharpStatement"/>.</returns>
        public static ForCSharpStatement For(IEnumerable <BinaryExpression> initializers, Expression test, IEnumerable <Expression> iterators, Expression body, LabelTarget @break, LabelTarget @continue)
        {
            ValidateLoop(test, body, @break, @continue, optionalTest: true);

            // NB: While C# requires all initializers to be of the same type, we don't quite need that restriction here.
            //     This can be revisited. We will check whether all initializers are simple assignments though.

            var initializerList = initializers.ToReadOnly <Expression>();
            var uniqueVariables = new HashSet <ParameterExpression>();
            var variables       = new List <ParameterExpression>();

            foreach (BinaryExpression initializer in initializerList)
            {
                if (initializer.NodeType != ExpressionType.Assign || initializer.Left.NodeType != ExpressionType.Parameter)
                {
                    throw Error.InvalidInitializer();
                }

                var variable = (ParameterExpression)initializer.Left;

                if (!uniqueVariables.Add(variable))
                {
                    throw LinqError.DuplicateVariable(variable);
                }

                // NB: We keep them in the order specified and don't rely on the hash set.
                variables.Add(variable);
            }

            var variableList = variables.ToReadOnly();

            var iteratorList = iterators.ToReadOnly();

            return(ForCSharpStatement.Make(variableList, initializerList, test, iteratorList, body, @break, @continue));
        }
コード例 #3
0
        /// <summary>
        /// Creates an expression representing a unary assignment operation.
        /// </summary>
        /// <param name="unaryType">The type of assignment represented.</param>
        /// <param name="operand">The operand of the assignment operation, i.e. the assignment target.</param>
        /// <param name="method">The method implementing the assignment operation.</param>
        /// <returns>A new <see cref="AssignUnaryCSharpExpression"/> instance representing the unary assignment.</returns>
        public static AssignUnaryCSharpExpression MakeUnaryAssign(CSharpExpressionType unaryType, Expression operand, MethodInfo method)
        {
            switch (unaryType)
            {
            case CSharpExpressionType.PreIncrementAssign:
                return(PreIncrementAssign(operand, method));

            case CSharpExpressionType.PreIncrementAssignChecked:
                return(PreIncrementAssignChecked(operand, method));

            case CSharpExpressionType.PreDecrementAssign:
                return(PreDecrementAssign(operand, method));

            case CSharpExpressionType.PreDecrementAssignChecked:
                return(PreDecrementAssignChecked(operand, method));

            case CSharpExpressionType.PostIncrementAssign:
                return(PostIncrementAssign(operand, method));

            case CSharpExpressionType.PostIncrementAssignChecked:
                return(PostIncrementAssignChecked(operand, method));

            case CSharpExpressionType.PostDecrementAssign:
                return(PostDecrementAssign(operand, method));

            case CSharpExpressionType.PostDecrementAssignChecked:
                return(PostDecrementAssignChecked(operand, method));
            }

            throw LinqError.UnhandledUnary(unaryType);
        }
コード例 #4
0
        /// <summary>
        /// Creates a <see cref="ForCSharpStatement"/> that represents a for loop.
        /// </summary>
        /// <param name="variables">The variables in scope of the loop.</param>
        /// <param name="initializers">The loop initializers.</param>
        /// <param name="test">The condition of the loop.</param>
        /// <param name="iterators">The loop iterators.</param>
        /// <param name="body">The body of the loop.</param>
        /// <param name="break">The break target used by the loop body.</param>
        /// <param name="continue">The continue target used by the loop body.</param>
        /// <returns>The created <see cref="ForCSharpStatement"/>.</returns>
        public static ForCSharpStatement For(IEnumerable <ParameterExpression> variables, IEnumerable <Expression> initializers, Expression test, IEnumerable <Expression> iterators, Expression body, LabelTarget @break, LabelTarget @continue)
        {
            ValidateLoop(test, body, @break, @continue, optionalTest: true);

            // NB: While C# requires all initializers to be of the same type, we don't quite need that restriction here.
            //     This can be revisited. We will check whether all initializers are simple assignments though.

            var variableList = variables.ToReadOnly();

            var initializerList = initializers.ToReadOnly <Expression>();

            RequiresNotNullItems(initializerList, nameof(initializers));

            var uniqueVariables = new HashSet <ParameterExpression>();

            foreach (var variable in variableList)
            {
                if (!uniqueVariables.Add(variable))
                {
                    throw LinqError.DuplicateVariable(variable);
                }
            }

            var iteratorList = iterators.ToReadOnly();

            RequiresNotNullItems(iteratorList, nameof(iterators));

            return(ForCSharpStatement.Make(variableList, initializerList, test, iteratorList, body, @break, @continue));
        }
        public static ConditionalMemberCSharpExpression ConditionalProperty(Expression expression, PropertyInfo property)
        {
            RequiresCanRead(expression, nameof(expression));
            ContractUtils.RequiresNotNull(property, nameof(property));

            if (!property.CanRead)
            {
                throw Error.ConditionalAccessRequiresReadableProperty();
            }

            if (property.GetIndexParameters().Length != 0)
            {
                throw Error.ConditionalAccessRequiresReadableProperty();
            }

            if (property.GetGetMethod(true).IsStatic)
            {
                throw Error.ConditionalAccessRequiresNonStaticMember();
            }

            var type = expression.Type.GetNonNullReceiverType();

            if (!TypeUtils.IsValidInstanceType(property, type))
            {
                throw LinqError.PropertyNotDefinedForType(property, type);
            }

            return(ConditionalMemberCSharpExpression.Make(expression, property));
        }
コード例 #6
0
        public static UsingCSharpStatement Using(ParameterExpression variable, Expression resource, Expression body)
        {
            RequiresCanRead(resource, nameof(resource));
            RequiresCanRead(body, nameof(body));

            var resourceType = resource.Type;

            if (variable != null)
            {
                var variableType = variable.Type;

                ValidateType(variableType);
                ValidateType(resourceType);

                // NB: No non-null value to nullable value assignment allowed here. This is consistent with Assign,
                //     and the C# compiler should insert the Convert node.
                if (!AreReferenceAssignable(variableType, resourceType))
                {
                    throw LinqError.ExpressionTypeDoesNotMatchAssignment(resourceType, variableType);
                }
            }

            var resourceTypeNonNull = resourceType.GetNonNullableType();

            // NB: We don't handle implicit conversions here; the C# compiler can emit a Convert node,
            //     just like it does for those type of conversions in various other places.
            if (!typeof(IDisposable).IsAssignableFrom(resourceTypeNonNull))
            {
                throw LinqError.ExpressionTypeDoesNotMatchAssignment(resourceTypeNonNull, typeof(IDisposable));
            }

            return(new UsingCSharpStatement(variable, resource, body));
        }
コード例 #7
0
        public static GotoLabelCSharpStatement GotoLabel(LabelTarget target)
        {
            RequiresNotNull(target, nameof(target));

            if (target.Type != typeof(void))
            {
                throw LinqError.LabelTypeMustBeVoid();
            }

            return(new GotoLabelCSharpStatement(target));
        }
コード例 #8
0
        /// <summary>
        /// Reduces the pattern by applying it the specified object.
        /// </summary>
        /// <param name="object">The object to match the pattern against.</param>
        /// <returns>The expression representing the pattern applied to the specified object.</returns>
        internal override Expression Reduce(Expression @object)
        {
            if (!AreReferenceAssignable(InputType, @object.Type))
            {
                throw LinqError.ExpressionTypeDoesNotMatchAssignment(@object.Type, InputType);
            }

            // NB: RecursiveCSharpPattern has a peephole optimization for the pattern below.

            // NB: Ensure any side-effects in evaluating @object are retained.
            return(PatternHelpers.Reduce(@object, _ => ConstantTrue));
        }
コード例 #9
0
        /// <summary>
        /// Creates a <see cref="ConditionalMemberCSharpExpression" /> that represents a conditional (null-propagating) member lookup.
        /// </summary>
        /// <param name="expression">An <see cref="Expression" /> that specifies the instance to access the member of.</param>
        /// <param name="member">The <see cref="MemberInfo" /> representing the member to access conditionally.</param>
        /// <returns>A <see cref="ConditionalMemberCSharpExpression" /> that has the <see cref="CSharpNodeType" /> property equal to <see cref="CSharpExpressionType.ConditionalAccess" /> and the <see cref="ConditionalAccessCSharpExpression{MemberExpression}.Receiver" /> and <see cref="Microsoft.CSharp.Expressions.ConditionalMemberCSharpExpression.Member" /> properties set to the specified values.</returns>
        public static ConditionalMemberCSharpExpression MakeConditionalMemberAccess(Expression expression, MemberInfo member)
        {
            RequiresNotNull(member, nameof(member));

            return(member switch
            {
                FieldInfo fieldInfo => ConditionalField(expression, fieldInfo),
                PropertyInfo propertyInfo => ConditionalProperty(expression, propertyInfo),

                // NB: LINQ doesn't allow a MethodInfo for a property getter here either; should we change this?
                _ => throw LinqError.MemberNotFieldOrProperty(member)
            });
コード例 #10
0
        /// <summary>
        /// Creates a catch block.
        /// </summary>
        /// <param name="variables">The variables introduced by the catch block.</param>
        /// <param name="type">The type of the exceptions to handle.</param>
        /// <param name="variable">The variable to assign a caught exception to.</param>
        /// <param name="body">The body of the catch block.</param>
        /// <param name="filter">The filter to apply.</param>
        /// <returns>The created <see cref="CSharpCatchBlock"/>.</returns>
        public static CSharpCatchBlock MakeCatchBlock(IEnumerable <ParameterExpression> variables, Type type, ParameterExpression variable, Expression body, Expression filter)
        {
            var variablesList = CheckUniqueVariables(variables, nameof(variables));

            Requires(variable == null || AreEquivalent(variable.Type, type), nameof(variable));

            if (variable != null)
            {
                if (variable.IsByRef)
                {
                    throw LinqError.VariableMustNotBeByRef(variable, variable.Type);
                }

                // REVIEW: See UsingCSharpStatement for a similar situation.

                if (!variablesList.Contains(variable))
                {
                    throw Error.CatchVariableNotInScope(variable);
                }

                if (type == null)
                {
                    type = variable.Type;
                }
                else if (!AreEquivalent(type, variable.Type))
                {
                    throw Error.CatchTypeNotEquivalentWithVariableType(type, variable.Type);
                }
            }
            else if (type != null)
            {
                ValidateType(type);
            }
            else
            {
                type = typeof(object); // NB: Used to catch all.
            }

            RequiresCanRead(body, nameof(body));

            if (filter != null)
            {
                RequiresCanRead(filter, nameof(filter));

                if (filter.Type != typeof(bool))
                {
                    throw LinqError.ArgumentMustBeBoolean();
                }
            }

            return(new CSharpCatchBlock(variablesList, type, variable, body, filter));
        }
コード例 #11
0
        /// <summary>
        /// Creates a <see cref="WithCSharpExpression"/> that represents a with expression.
        /// </summary>
        /// <param name="object">The expression representing the object to clone and mutate.</param>
        /// <param name="clone">The method used to clone the object.</param>
        /// <param name="initializers">The initializers used to mutate the cloned object.</param>
        /// <returns>The created <see cref="WithCSharpExpression"/>.</returns>
        public static WithCSharpExpression With(Expression @object, MethodInfo clone, IEnumerable <MemberInitializer> initializers)
        {
            RequiresNotNull(@object, nameof(@object));
            RequiresNotNull(initializers, nameof(initializers));

            var initializersCollection = initializers.ToReadOnly();

            ValidateWithReceiverAndInitializers(@object, initializersCollection, requiresCanAssign: true);

            if (@object.Type.IsValueType)
            {
                if (clone != null)
                {
                    throw Error.WithExpressionCannotHaveCloneForValueType(@object.Type);
                }
            }
            else
            {
                clone ??= @object.Type.GetNonGenericMethod("Clone", BindingFlags.Public | BindingFlags.Instance, Type.EmptyTypes);

                if (clone == null)
                {
                    throw Error.WithExpressionShouldHaveClone(@object.Type);
                }

                ValidateMethodInfo(clone);

                if (clone.IsStatic)
                {
                    throw Error.CloneMethodMustNotBeStatic(clone.Name);
                }

                if (!clone.DeclaringType.IsAssignableFrom(@object.Type))
                {
                    throw LinqError.NotAMemberOfType(clone.Name, @object.Type);
                }

                if (clone.GetParametersCached().Length != 0)
                {
                    throw Error.CloneMethodShouldHaveNoParameters(clone.Name);
                }

                if (!HasReferenceConversion(clone.ReturnType, @object.Type))
                {
                    throw Error.CloneMethodShouldReturnCompatibleType(clone.Name, @object.Type);
                }
            }

            return(new WithCSharpExpression(@object, initializersCollection, clone, members: null));
        }
コード例 #12
0
        /// <summary>
        /// Creates a <see cref="LocalDeclaration"/> that represents a local declaration.
        /// </summary>
        /// <param name="variable">The variable that is being declared.</param>
        /// <param name="expression">The initializer expression representing the value to assign to the variable.</param>
        /// <returns>The created <see cref="LocalDeclaration"/>.</returns>
        public static LocalDeclaration LocalDeclaration(ParameterExpression variable, Expression expression)
        {
            RequiresNotNull(variable, nameof(variable));
            RequiresCanRead(expression, nameof(expression));

            // NB: No non-null value to nullable value assignment allowed here. This is consistent with Assign,
            //     and the C# compiler should insert the Convert node.
            if (!AreReferenceAssignable(variable.Type, expression.Type))
            {
                throw LinqError.ExpressionTypeDoesNotMatchAssignment(expression.Type, variable.Type);
            }

            return(new LocalDeclaration(variable, expression));
        }
コード例 #13
0
        /// <summary>
        /// Creates an expression representing a binary assignment operation.
        /// </summary>
        /// <param name="binaryType">The type of assignment represented.</param>
        /// <param name="left">The left operand of the assignment operation, i.e. the assignment target.</param>
        /// <param name="right">The right operation of the assignment operation.</param>
        /// <param name="method">The method implementing the assignment operation.</param>
        /// <param name="leftConversion">The conversion function used to convert the left hand side of the compound assignment prior to use by the underlying operation.</param>
        /// <param name="finalConversion">The conversion function used to convert the result of the underlying operation prior to assignment to the left hand side of the compound assignment operation.</param>
        /// <returns>A new <see cref="AssignBinaryCSharpExpression"/> instance representing the binary assignment.</returns>
        public static AssignBinaryCSharpExpression MakeBinaryAssign(CSharpExpressionType binaryType, Expression left, Expression right, MethodInfo method, LambdaExpression leftConversion, LambdaExpression finalConversion)
        {
            switch (binaryType)
            {
            case CSharpExpressionType.Assign:
                return(Assign(left, right));

            case CSharpExpressionType.AddAssign:
                return(AddAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.AndAssign:
                return(AndAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.DivideAssign:
                return(DivideAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.ExclusiveOrAssign:
                return(ExclusiveOrAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.LeftShiftAssign:
                return(LeftShiftAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.ModuloAssign:
                return(ModuloAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.MultiplyAssign:
                return(MultiplyAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.OrAssign:
                return(OrAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.RightShiftAssign:
                return(RightShiftAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.SubtractAssign:
                return(SubtractAssign(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.AddAssignChecked:
                return(AddAssignChecked(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.MultiplyAssignChecked:
                return(MultiplyAssignChecked(left, right, method, leftConversion, finalConversion));

            case CSharpExpressionType.SubtractAssignChecked:
                return(SubtractAssignChecked(left, right, method, leftConversion, finalConversion));
            }

            throw LinqError.UnhandledBinary(binaryType);
        }
コード例 #14
0
        internal static BinaryExpression FunctionalOp(CSharpExpressionType binaryType, Expression left, Expression right, MethodInfo method)
        {
            switch (binaryType)
            {
            case CSharpExpressionType.Assign:
                return(Expression.Assign(left, right));

            case CSharpExpressionType.AddAssign:
                return(Expression.Add(left, right, method));

            case CSharpExpressionType.AndAssign:
                return(Expression.And(left, right, method));

            case CSharpExpressionType.DivideAssign:
                return(Expression.Divide(left, right, method));

            case CSharpExpressionType.ExclusiveOrAssign:
                return(Expression.ExclusiveOr(left, right, method));

            case CSharpExpressionType.LeftShiftAssign:
                return(Expression.LeftShift(left, right, method));

            case CSharpExpressionType.ModuloAssign:
                return(Expression.Modulo(left, right, method));

            case CSharpExpressionType.MultiplyAssign:
                return(Expression.Multiply(left, right, method));

            case CSharpExpressionType.OrAssign:
                return(Expression.Or(left, right, method));

            case CSharpExpressionType.RightShiftAssign:
                return(Expression.RightShift(left, right, method));

            case CSharpExpressionType.SubtractAssign:
                return(Expression.Subtract(left, right, method));

            case CSharpExpressionType.AddAssignChecked:
                return(Expression.AddChecked(left, right, method));

            case CSharpExpressionType.MultiplyAssignChecked:
                return(Expression.MultiplyChecked(left, right, method));

            case CSharpExpressionType.SubtractAssignChecked:
                return(Expression.SubtractChecked(left, right, method));
            }

            throw LinqError.UnhandledBinary(binaryType);
        }
コード例 #15
0
        private static void ValidateCondition(Expression test, bool optionalTest = false)
        {
            if (optionalTest && test == null)
            {
                return;
            }

            // TODO: We can be more flexible and allow the rules in C# spec 7.20.
            //       Note that this behavior is the same as IfThen, but we could also add C# specific nodes for those,
            //       with the more flexible construction behavior.
            if (test.Type != typeof(bool))
            {
                throw LinqError.ArgumentMustBeBoolean();
            }
        }
コード例 #16
0
        /// <summary>
        /// Creates an object holding type information about a pattern.
        /// </summary>
        /// <param name="info">The underlying type information.</param>
        /// <param name="variable">The CSharpObjectPatternInfo to assign to upon successfully matching the associated pattern.</param>
        /// <returns>A <see cref="CSharpPatternInfo" /> object holding type information about a pattern.</returns>
        public static CSharpObjectPatternInfo ObjectPatternInfo(CSharpPatternInfo info, ParameterExpression variable)
        {
            info ??= PatternInfo(typeof(object), variable?.Type ?? typeof(object));

            if (variable != null)
            {
                if (variable.Type.IsByRef)
                {
                    throw LinqError.VariableMustNotBeByRef(variable, variable.Type);
                }

                RequiresCompatiblePatternTypes(info.NarrowedType, variable.Type);
            }

            return(new CSharpObjectPatternInfo(info, variable));
        }
コード例 #17
0
        private static void ValidateGetAwaiterMethod(Type operandType, MethodInfo getAwaiterMethod)
        {
            ValidateMethodInfo(getAwaiterMethod);

            // NB: We don't check whether the name of the method is GetAwaiter, just like we don't check the name of
            //     operator op_* methods in Binary and Unary node factories in LINQ. We could tighten this, but there
            //     is no harm in letting an advanced used specify another method that obeys to the awaiter pattern
            //     other than the predescribed method name. The C# compiler will always specify the MethodInfo in the
            //     emitted factory call.

            var getAwaiterParams = getAwaiterMethod.GetParametersCached();

            if (getAwaiterMethod.IsStatic)
            {
                if (getAwaiterParams.Length != 1)
                {
                    throw Error.GetAwaiterShouldTakeZeroParameters();
                }

                var firstParam = getAwaiterParams[0];

                if (!TypeUtils.AreReferenceAssignable(firstParam.ParameterType, operandType))
                {
                    throw LinqError.ExpressionTypeDoesNotMatchParameter(operandType, firstParam.ParameterType);
                }
            }
            else
            {
                if (getAwaiterParams.Length != 0)
                {
                    throw Error.GetAwaiterShouldTakeZeroParameters();
                }

                if (getAwaiterMethod.IsGenericMethod)
                {
                    throw Error.GetAwaiterShouldNotBeGeneric();
                }
            }

            var returnType = getAwaiterMethod.ReturnType;

            if (returnType == typeof(void) || returnType.IsByRef || returnType.IsPointer)
            {
                throw Error.GetAwaiterShouldReturnAwaiterType();
            }
        }
コード例 #18
0
        internal static void ValidateLoop(Expression body, LabelTarget @break, LabelTarget @continue)
        {
            if (@break != null && @break.Type != typeof(void))
            {
                // DESIGN: C# statement behavior; can be revisited.
                throw LinqError.LabelTypeMustBeVoid();
            }

            if (@continue != null && @continue.Type != typeof(void))
            {
                throw LinqError.LabelTypeMustBeVoid();
            }

            if (@break != null && @continue != null && @break == @continue)
            {
                throw Error.DuplicateLabels();
            }
        }
コード例 #19
0
        public static UsingCSharpStatement Using(ParameterExpression variable, Expression resource, Expression body)
        {
            var resourceType = resource.Type;

            if (variable != null)
            {
                var variableType = variable.Type;

                // NB: No non-null value to nullable value assignment allowed here. This is consistent with Assign,
                //     and the C# compiler should insert the Convert node.
                if (!AreReferenceAssignable(variableType, resourceType))
                {
                    throw LinqError.ExpressionTypeDoesNotMatchAssignment(resourceType, variableType);
                }
            }

            return(new UsingCSharpStatement(variable, resource, body));
        }
コード例 #20
0
        private static Type ValidateConversion(CSharpExpressionType nodeType, Type inputType, LambdaExpression conversion)
        {
            var invoke = conversion.Type.GetMethod("Invoke");

            var invokeParameters = invoke.GetParametersCached();

            if (invokeParameters.Length != 1)
            {
                throw LinqError.IncorrectNumberOfMethodCallArguments(conversion);
            }

            if (!TypeUtils.AreEquivalent(invokeParameters[0].ParameterType, inputType))
            {
                throw LinqError.OperandTypesDoNotMatchParameters(nodeType, conversion.ToString());
            }

            return(invoke.ReturnType);
        }
コード例 #21
0
        /// <summary>
        /// Creates a <see cref="WithCSharpExpression"/> that represents a with expression applied to an anonymous type.
        /// </summary>
        /// <param name="object">The expression representing the object to clone and mutate.</param>
        /// <param name="members">The members of the anonymous type in the order of their assignment by the constructor parameters.</param>
        /// <param name="initializers">The initializers used to mutate the cloned object.</param>
        /// <returns>The created <see cref="WithCSharpExpression"/>.</returns>
        public static WithCSharpExpression With(Expression @object, IEnumerable <MemberInfo> members, IEnumerable <MemberInitializer> initializers)
        {
            RequiresNotNull(@object, nameof(@object));
            RequiresNotNull(members, nameof(members));
            RequiresNotNull(initializers, nameof(initializers));

            var membersCollection      = members.ToReadOnly();
            var initializersCollection = initializers.ToReadOnly();

            ValidateWithReceiverAndInitializers(@object, initializersCollection, requiresCanAssign: false);

            var membersCount = membersCollection.Count;

            var newMembers  = new MemberInfo[membersCount];
            var memberTypes = new Type[membersCount];

            for (var i = 0; i < membersCount; i++)
            {
                var member = membersCollection[i];

                RequiresNotNull(member, nameof(member));

                if (!AreEquivalent(member.DeclaringType, @object.Type))
                {
                    throw LinqError.ArgumentMemberNotDeclOnType(member.Name, @object.Type.Name);
                }

                ValidateAnonymousTypeMember(ref member, out var memberType);

                newMembers[i]  = member;
                memberTypes[i] = memberType;
            }

            membersCollection = newMembers.ToReadOnly();

            var ctor = @object.Type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, binder: null, memberTypes, modifiers: null);

            if (ctor == null)
            {
                throw Error.NoAnonymousTypeConstructorFound(@object.Type);
            }

            return(new WithCSharpExpression(@object, initializersCollection, clone: null, membersCollection));
        }
コード例 #22
0
        /// <summary>
        /// Creates an expression representing an array access operation.
        /// </summary>
        /// <param name="array">The array to access.</param>
        /// <param name="indexes">The indexes used to access the array.</param>
        /// <returns>A new <see cref="ArrayAccessCSharpExpression"/> instance representing the array access operation.</returns>
        public static new ArrayAccessCSharpExpression ArrayAccess(Expression array, IEnumerable <Expression> indexes)
        {
            RequiresCanRead(array, nameof(array));

            var arrayType = array.Type;

            if (!arrayType.IsArray)
            {
                throw LinqError.ArgumentMustBeArray();
            }

            var indexesList = indexes.ToReadOnly();

            if (arrayType.GetArrayRank() != indexesList.Count)
            {
                throw LinqError.IncorrectNumberOfIndexes();
            }

            foreach (var index in indexesList)
            {
                RequiresCanRead(index, nameof(indexes));
            }

            if (indexesList.Count == 1)
            {
                var index = indexesList[0];

                if (index.Type == typeof(Index) || index.Type == typeof(Range))
                {
                    return(new ArrayAccessCSharpExpression(array, indexesList));
                }
            }

            foreach (var index in indexesList)
            {
                if (index.Type != typeof(int))
                {
                    throw LinqError.ArgumentMustBeArrayIndexType();
                }
            }

            return(new ArrayAccessCSharpExpression(array, indexesList));
        }
コード例 #23
0
        /// <summary>
        /// Creates a <see cref="TryCSharpStatement" /> representing a try block with zero or more catch blocks and an optional finally block.
        /// </summary>
        /// <param name="tryBlock">The try block.</param>
        /// <param name="handlerBlocks">The array of zero or more <see cref="CSharpCatchBlock" /> expressions representing the catch blocks to be associated with the try block.</param>
        /// <param name="finallyBlock">The finally block.</param>
        /// <returns>The created <see cref="TryCSharpStatement" />.</returns>
        public static TryCSharpStatement Try(Expression tryBlock, IEnumerable <CSharpCatchBlock> handlerBlocks, Expression finallyBlock)
        {
            RequiresCanRead(tryBlock, nameof(tryBlock));

            var handlers = handlerBlocks.ToReadOnly();

            RequiresNotNullItems(handlers, nameof(handlerBlocks));

            if (finallyBlock != null)
            {
                RequiresCanRead(finallyBlock, nameof(finallyBlock));
            }
            else if (handlers.Count == 0)
            {
                throw LinqError.TryMustHaveCatchFinallyOrFault();
            }

            return(new TryCSharpStatement(tryBlock, handlers, finallyBlock));
        }
        public static ConditionalMemberCSharpExpression ConditionalField(Expression expression, FieldInfo field)
        {
            RequiresCanRead(expression, nameof(expression));
            ContractUtils.RequiresNotNull(field, nameof(field));

            if (field.IsStatic)
            {
                throw Error.ConditionalAccessRequiresNonStaticMember();
            }

            var type = expression.Type.GetNonNullReceiverType();

            if (!TypeUtils1.AreReferenceAssignable(field.DeclaringType, type))
            {
                throw LinqError.FieldInfoNotDefinedForType(field.DeclaringType, field.Name, type);
            }

            return(ConditionalMemberCSharpExpression.Make(expression, field));
        }
コード例 #25
0
        /// <summary>
        /// Creates a <see cref="BlockCSharpExpression"/> that represents a block.
        /// </summary>
        /// <param name="variables">The variables declared in the block.</param>
        /// <param name="statements">The statements in the block.</param>
        /// <param name="returnLabel">The return label used to exist the block.</param>
        /// <returns>The created <see cref="BlockCSharpExpression"/>.</returns>
        public static BlockCSharpExpression Block(IEnumerable <ParameterExpression> variables, IEnumerable <Expression> statements, LabelTarget returnLabel)
        {
            var variablesList = variables.ToReadOnly();

            var uniqueVariables = new HashSet <ParameterExpression>();

            foreach (var variable in variablesList)
            {
                if (!uniqueVariables.Add(variable))
                {
                    throw LinqError.DuplicateVariable(variable);
                }
            }

            var statementsList = statements.ToReadOnly();

            RequiresNotNullItems(statementsList, nameof(statements));

            return(new BlockCSharpExpression(variablesList, statementsList, returnLabel));
        }
コード例 #26
0
        public static AsyncLambdaCSharpExpression AsyncLambda(Expression body, IEnumerable <ParameterExpression> parameters)
        {
            ContractUtils.RequiresNotNull(body, nameof(body));

            var parameterList = parameters.ToReadOnly();

            var count = parameterList.Count;
            var types = new Type[count + 1];

            if (count > 0)
            {
                var set = new Set <ParameterExpression>(count);

                for (var i = 0; i < count; i++)
                {
                    var parameter = parameterList[i];

                    ValidateAsyncParameter(parameter);

                    types[i] = parameter.Type;

                    if (set.Contains(parameter))
                    {
                        throw LinqError.DuplicateVariable(parameter);
                    }

                    set.Add(parameter);
                }
            }

            if (body.Type == typeof(void))
            {
                types[count] = typeof(Task); // REVIEW: OK to default to Task?
            }
            else
            {
                types[count] = typeof(Task <>).MakeGenericType(body.Type);
            }

            return(CreateAsyncLambda(DelegateHelpers.MakeDelegateType(types), body, parameterList));
        }
コード例 #27
0
        internal static ReadOnlyCollection <ParameterExpression> CheckUniqueVariables(IEnumerable <ParameterExpression> variables, string paramName)
        {
            var variablesList = variables.ToReadOnly();

            if (variablesList.Count > 0)
            {
                RequiresNotNullItems(variablesList, paramName);

                var uniqueVariables = new HashSet <ParameterExpression>(variablesList.Count);

                foreach (var variable in variablesList)
                {
                    if (!uniqueVariables.Add(variable))
                    {
                        throw LinqError.DuplicateVariable(variable);
                    }
                }
            }

            return(variablesList);
        }
        public static ConditionalMemberCSharpExpression ConditionalProperty(Expression expression, string propertyName)
        {
            RequiresCanRead(expression, nameof(expression));
            ContractUtils.RequiresNotNull(propertyName, nameof(propertyName));

            var type = expression.Type.GetNonNullReceiverType();

            var property = type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);

            if (property == null)
            {
                property = type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
            }

            if (property == null)
            {
                throw LinqError.InstancePropertyNotDefinedForType(propertyName, type);
            }

            return(ConditionalProperty(expression, property));
        }
        public static ConditionalMemberCSharpExpression ConditionalField(Expression expression, string fieldName)
        {
            RequiresCanRead(expression, nameof(expression));
            ContractUtils.RequiresNotNull(fieldName, nameof(fieldName));

            var type = expression.Type.GetNonNullReceiverType();

            var field = type.GetField(fieldName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);

            if (field == null)
            {
                field = type.GetField(fieldName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
            }

            if (field == null)
            {
                throw LinqError.InstanceFieldNotDefinedForType(fieldName, type);
            }

            return(ConditionalField(expression, field));
        }
コード例 #30
0
        private static void ValidateWithReceiverAndInitializers(Expression @object, ReadOnlyCollection <MemberInitializer> initializers, bool requiresCanAssign)
        {
            RequiresCanRead(@object, nameof(@object));

            for (int i = 0, count = initializers.Count; i < count; i++)
            {
                var initializer = initializers[i];

                RequiresNotNull(initializer, nameof(initializers));

                var member = initializer.Member;

                if (!member.DeclaringType.IsAssignableFrom(@object.Type))
                {
                    throw LinqError.NotAMemberOfType(member.Name, @object.Type);
                }

                if (requiresCanAssign)
                {
                    switch (member)
                    {
                    case FieldInfo f:
                        if (f.IsInitOnly || f.IsLiteral)
                        {
                            throw Error.MemberInitializerMemberMustBeWriteable(member.Name);
                        }

                        break;

                    case PropertyInfo p:
                        if (!p.CanWrite)
                        {
                            throw Error.MemberInitializerMemberMustBeWriteable(member.Name);
                        }

                        break;
                    }
                }
            }
        }