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
- Guid.cs
- MemoryStream.cs
- UnknownWrapper.cs
- DataRecordInfo.cs
- ListViewItemEventArgs.cs
- HeaderedItemsControl.cs
- FixedPosition.cs
- HotSpotCollection.cs
- ScaleTransform.cs
- SecurityRuntime.cs
- StrongNameKeyPair.cs
- EntityDataSourceSelectingEventArgs.cs
- XPathParser.cs
- GridViewRowEventArgs.cs
- ClientScriptItem.cs
- DataRowComparer.cs
- Encoder.cs
- MembershipUser.cs
- ComponentCollection.cs
- BitmapSizeOptions.cs
- FillRuleValidation.cs
- LineServicesCallbacks.cs
- IsolatedStorageFile.cs
- BindingMemberInfo.cs
- DesignerSelectionListAdapter.cs
- ExpressionEditorAttribute.cs
- MsmqBindingFilter.cs
- UrlMapping.cs
- Serializer.cs
- ServiceParser.cs
- MinMaxParagraphWidth.cs
- DataTablePropertyDescriptor.cs
- DeviceSpecificChoice.cs
- IpcClientManager.cs
- RenderingBiasValidation.cs
- TreeNodeCollection.cs
- Completion.cs
- DesignerActionTextItem.cs
- _OSSOCK.cs
- CategoriesDocument.cs
- SettingsBindableAttribute.cs
- PrimitiveXmlSerializers.cs
- TransactionInformation.cs
- HtmlSelect.cs
- InvalidEnumArgumentException.cs
- InfoCardRSACryptoProvider.cs
- SignatureHelper.cs
- ListViewInsertionMark.cs
- VectorKeyFrameCollection.cs
- SessionIDManager.cs
- DrawingCollection.cs
- UniqueConstraint.cs
- ObjectTag.cs
- LocalBuilder.cs
- SystemResourceKey.cs
- ShortcutKeysEditor.cs
- QuadraticEase.cs
- PropertyMetadata.cs
- RoutingUtilities.cs
- ResourceAssociationSet.cs
- PolyBezierSegmentFigureLogic.cs
- SQLInt32Storage.cs
- SupportsEventValidationAttribute.cs
- MergeLocalizationDirectives.cs
- Int32EqualityComparer.cs
- DispatcherExceptionEventArgs.cs
- DBParameter.cs
- GridViewColumnHeaderAutomationPeer.cs
- DesignerVerb.cs
- AvtEvent.cs
- HttpStreams.cs
- EventProxy.cs
- ZipIOLocalFileHeader.cs
- CodeSnippetExpression.cs
- Selection.cs
- StatusBarItem.cs
- DataGridViewTopRowAccessibleObject.cs
- DirectoryNotFoundException.cs
- PageCache.cs
- WebUtil.cs
- _UncName.cs
- MSHTMLHost.cs
- DocumentReference.cs
- ApplyImportsAction.cs
- ContainsRowNumberChecker.cs
- DefaultBindingPropertyAttribute.cs
- AppSettingsExpressionBuilder.cs
- DataSourceConverter.cs
- ConnectionPointGlyph.cs
- SqlParameterCollection.cs
- PropagatorResult.cs
- XmlQueryRuntime.cs
- XmlAttributeProperties.cs
- AddressingVersion.cs
- ScriptReferenceEventArgs.cs
- SpecialFolderEnumConverter.cs
- NotificationContext.cs
- clipboard.cs
- CookieProtection.cs
- RequestCachingSection.cs