Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / MemberAssignmentAnalysis.cs / 1305376 / MemberAssignmentAnalysis.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a class that can analyze a member assignment to determine // how deep / which entity types the assignment is coming from. // //--------------------------------------------------------------------- namespace System.Data.Services.Client { #region Namespaces. using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; #endregion Namespaces. ////// Use this class to analyze a member assignment and figure out the /// target path for a member-init on an entity type. /// ////// This class will also detect cases in which the assignment /// expression refers to cases which we shouldn't handle during /// materialization, such as references to multiple entity types /// as sources (or refering to no source at all). /// internal class MemberAssignmentAnalysis : ALinqExpressionVisitor { #region Fields. ///Empty expression array; immutable. internal static readonly Expression[] EmptyExpressionArray = new Expression[0]; ///Entity in scope for the lambda that's providing the parameter. private readonly Expression entity; ///A non-null value when incompatible paths were found for an entity initializer. private Exception incompatibleAssignmentsException; ///Whether multiple paths were found for this analysis. private bool multiplePathsFound; ///Path traversed from the entry field. private ListpathFromEntity; #endregion Fields. #region Constructor. /// Initializes a new /// Entity in scope for the lambda that's providing the parameter. private MemberAssignmentAnalysis(Expression entity) { Debug.Assert(entity != null, "entity != null"); this.entity = entity; this.pathFromEntity = new Listinstance. (); } #endregion Constructor. #region Properties. /// A non-null value when incompatible paths were found for an entity initializer. internal Exception IncompatibleAssignmentsException { get { return this.incompatibleAssignmentsException; } } ///Whether multiple paths were found during analysis. internal bool MultiplePathsFound { get { return this.multiplePathsFound; } } #endregion Properites. #region Methods. ///Analyzes an assignment from a member-init expression. /// Entity in scope for the lambda that's providing the parameter. /// The expression to analyze. ///The analysis results. internal static MemberAssignmentAnalysis Analyze(Expression entityInScope, Expression assignmentExpression) { Debug.Assert(entityInScope != null, "entityInScope != null"); Debug.Assert(assignmentExpression != null, "assignmentExpression != null"); MemberAssignmentAnalysis result = new MemberAssignmentAnalysis(entityInScope); result.Visit(assignmentExpression); return result; } ////// Checks whether the this and a /// Type being initialized. /// Previously seen member accesses (null if this is the first). ////// paths for assignments are compatible. /// An exception to be thrown if assignments are not compatible; null otherwise. ////// This method does not set the IncompatibleAssignmentsException property on either /// analysis instance. /// internal Exception CheckCompatibleAssignments(Type targetType, ref MemberAssignmentAnalysis previous) { if (previous == null) { previous = this; return null; } Expression[] previousExpressions = previous.GetExpressionsToTargetEntity(); Expression[] candidateExpressions = this.GetExpressionsToTargetEntity(); return CheckCompatibleAssignments(targetType, previousExpressions, candidateExpressions); } ///Visits the specified /// Expression to visit. ///. The visited expression. ///This method is overriden to short-circuit analysis once an error is found. internal override Expression Visit(Expression expression) { if (this.multiplePathsFound || this.incompatibleAssignmentsException != null) { return expression; } return base.Visit(expression); } ///Visits a conditional expression. /// Expression to visit. ///The same expression. ////// There are three expressions of interest: the Test, the IfTrue /// branch, and the IfFalse branch. If this is a NullCheck expression, /// then we can traverse the non-null branch, which will be the /// correct path of the resulting value. /// internal override Expression VisitConditional(ConditionalExpression c) { Expression result; var nullCheck = ResourceBinder.PatternRules.MatchNullCheck(this.entity, c); if (nullCheck.Match) { this.Visit(nullCheck.AssignExpression); result = c; } else { result = base.VisitConditional(c); } return result; } ///Parameter visit method. /// Parameter to visit. ///The same expression. internal override Expression VisitParameter(ParameterExpression p) { if (p == this.entity) { if (this.pathFromEntity.Count != 0) { this.multiplePathsFound = true; } else { this.pathFromEntity.Add(p); } } return p; } ///Visits a nested member init. /// Expression to visit. ///The same expression. internal override Expression VisitMemberInit(MemberInitExpression init) { Expression result = init; MemberAssignmentAnalysis previousNested = null; foreach (var binding in init.Bindings) { MemberAssignment assignment = binding as MemberAssignment; if (assignment == null) { continue; } MemberAssignmentAnalysis nested = MemberAssignmentAnalysis.Analyze(this.entity, assignment.Expression); if (nested.MultiplePathsFound) { this.multiplePathsFound = true; break; } // When we're visitng a nested entity initializer, we're exactly one level above that. Exception incompatibleException = nested.CheckCompatibleAssignments(init.Type, ref previousNested); if (incompatibleException != null) { this.incompatibleAssignmentsException = incompatibleException; break; } if (this.pathFromEntity.Count == 0) { this.pathFromEntity.AddRange(nested.GetExpressionsToTargetEntity()); } } return result; } ///Visits a member access expression. /// Access to visit. ///The same expression. internal override Expression VisitMemberAccess(MemberExpression m) { Expression result = base.VisitMemberAccess(m); if (this.pathFromEntity.Contains(m.Expression)) { this.pathFromEntity.Add(m); } return result; } ///Visits a method call expression. /// Method call to visit. ///The same call. internal override Expression VisitMethodCall(MethodCallExpression call) { // When we .Select(), the source of the enumeration is what we contribute // eg: p => p.Cities.Select(c => c) ::= Select(p.Cities, c => c); if (ReflectionUtil.IsSequenceMethod(call.Method, SequenceMethod.Select)) { this.Visit(call.Arguments[0]); return call; } return base.VisitMethodCall(call); } ///Gets the expressions that go beyond the last entity. ///An array of member expressions coming after the last entity. ///Currently a single member access is supported. internal Expression[] GetExpressionsBeyondTargetEntity() { Debug.Assert(!this.multiplePathsFound, "this.multiplePathsFound -- otherwise GetExpressionsToTargetEntity won't return reliable (consistent) results"); if (this.pathFromEntity.Count <= 1) { return EmptyExpressionArray; } Expression[] result = new Expression[1]; result[0] = this.pathFromEntity[this.pathFromEntity.Count - 1]; return result; } ///Gets the expressions that "walk down" to the last entity. ///An array of member expressions down to the last entity. internal Expression[] GetExpressionsToTargetEntity() { Debug.Assert(!this.multiplePathsFound, "this.multiplePathsFound -- otherwise GetExpressionsToTargetEntity won't return reliable (consistent) results"); if (this.pathFromEntity.Count <= 1) { return EmptyExpressionArray; } Expression[] result = new Expression[this.pathFromEntity.Count - 1]; for (int i = 0; i < result.Length; i++) { result[i] = this.pathFromEntity[i]; } return result; } ////// Checks whether the /// Type being initialized. /// Previously seen member accesses. /// Member assignments under evaluate. ///and /// paths for assignments are compatible. /// An exception to be thrown if assignments are not compatible; null otherwise. private static Exception CheckCompatibleAssignments(Type targetType, Expression[] previous, Expression[] candidate) { Debug.Assert(targetType != null, "targetType != null"); Debug.Assert(previous != null, "previous != null"); Debug.Assert(candidate != null, "candidate != null"); if (previous.Length != candidate.Length) { throw CheckCompatibleAssignmentsFail(targetType, previous, candidate); } for (int i = 0; i < previous.Length; i++) { Expression p = previous[i]; Expression c = candidate[i]; if (p.NodeType != c.NodeType) { throw CheckCompatibleAssignmentsFail(targetType, previous, candidate); } if (p == c) { continue; } if (p.NodeType != ExpressionType.MemberAccess) { return CheckCompatibleAssignmentsFail(targetType, previous, candidate); } if (((MemberExpression)p).Member.Name != ((MemberExpression)c).Member.Name) { return CheckCompatibleAssignmentsFail(targetType, previous, candidate); } } return null; } ///Creates an exception to be used when CheckCompatibleAssignment fails. /// Type being initialized. /// Previously seen member accesses. /// Member assignments under evaluate. ///A new exception with diagnostic information. private static Exception CheckCompatibleAssignmentsFail(Type targetType, Expression[] previous, Expression[] candidate) { Debug.Assert(targetType != null, "targetType != null"); Debug.Assert(previous != null, "previous != null"); Debug.Assert(candidate != null, "candidate != null"); string message = Strings.ALinq_ProjectionMemberAssignmentMismatch(targetType.FullName, previous.LastOrDefault(), candidate.LastOrDefault()); return new NotSupportedException(message); } #endregion Methods. } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EmbeddedObject.cs
- CustomCredentialPolicy.cs
- PolyQuadraticBezierSegment.cs
- EncoderExceptionFallback.cs
- FramingDecoders.cs
- SpellerHighlightLayer.cs
- AspCompat.cs
- DataListCommandEventArgs.cs
- SQLGuidStorage.cs
- XmlSchemaAll.cs
- BamlResourceSerializer.cs
- TextSelection.cs
- InputMethodStateTypeInfo.cs
- SourceFilter.cs
- SqlTopReducer.cs
- XmlDocument.cs
- VirtualDirectoryMapping.cs
- GridToolTip.cs
- MailBnfHelper.cs
- TextTreeUndo.cs
- ReadOnlyPropertyMetadata.cs
- DependencySource.cs
- PointLight.cs
- compensatingcollection.cs
- ChangePassword.cs
- Set.cs
- RequestResizeEvent.cs
- HttpStreamFormatter.cs
- TextEditorMouse.cs
- ReadOnlyDataSource.cs
- CryptoApi.cs
- UriParserTemplates.cs
- dsa.cs
- DataBoundControl.cs
- CreateUserWizard.cs
- MsmqTransportSecurity.cs
- XmlTextReaderImpl.cs
- DataSourceSelectArguments.cs
- XmlSubtreeReader.cs
- VisualStyleTypesAndProperties.cs
- PropertyInformation.cs
- InternalConfigSettingsFactory.cs
- ColumnMapProcessor.cs
- XmlQueryContext.cs
- OdbcRowUpdatingEvent.cs
- MultilineStringConverter.cs
- SchemaImporter.cs
- NumberAction.cs
- IdleTimeoutMonitor.cs
- ContainerUtilities.cs
- InvokeProviderWrapper.cs
- ClientApiGenerator.cs
- SqlConnectionString.cs
- QfeChecker.cs
- precedingquery.cs
- Int16Storage.cs
- BitmapSource.cs
- ExchangeUtilities.cs
- CultureInfo.cs
- EventManager.cs
- UserControl.cs
- SettingsPropertyWrongTypeException.cs
- HttpResponseBase.cs
- ThreadExceptionDialog.cs
- CurrencyManager.cs
- Pens.cs
- PropertyPushdownHelper.cs
- UpdateManifestForBrowserApplication.cs
- SystemIPAddressInformation.cs
- FixedTextPointer.cs
- SynchronizationScope.cs
- FacetValueContainer.cs
- DataGridViewCell.cs
- SafeSecurityHandles.cs
- ToolStripGripRenderEventArgs.cs
- DBSqlParserTableCollection.cs
- ClientCultureInfo.cs
- ResourceReferenceExpression.cs
- InfoCardRSACryptoProvider.cs
- PropertyInformation.cs
- MsmqEncryptionAlgorithm.cs
- TemplateControl.cs
- WinInetCache.cs
- ExceptionUtility.cs
- ValidatedMobileControlConverter.cs
- HtmlImage.cs
- BinarySerializer.cs
- PackWebResponse.cs
- PageFunction.cs
- AlignmentYValidation.cs
- ColumnResizeAdorner.cs
- ElementsClipboardData.cs
- SqlNodeAnnotations.cs
- UnsafeNativeMethods.cs
- Opcode.cs
- EntityContainerEmitter.cs
- Int64.cs
- VirtualizedItemPattern.cs
- CLSCompliantAttribute.cs
- TemplateBindingExtensionConverter.cs