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)); }
/// <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)); }
/// <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); }
/// <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)); }
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)); }
public static GotoLabelCSharpStatement GotoLabel(LabelTarget target) { RequiresNotNull(target, nameof(target)); if (target.Type != typeof(void)) { throw LinqError.LabelTypeMustBeVoid(); } return(new GotoLabelCSharpStatement(target)); }
/// <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)); }
/// <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) });
/// <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)); }
/// <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)); }
/// <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)); }
/// <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); }
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); }
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(); } }
/// <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)); }
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(); } }
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(); } }
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)); }
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); }
/// <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)); }
/// <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)); }
/// <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)); }
/// <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)); }
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)); }
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)); }
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; } } } }