Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / ALinq / ExpressionWriter.cs / 1305376 / ExpressionWriter.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Serializes sub-expressions as query options in the URI. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services.Client { #region Namespaces. using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq.Expressions; using System.Reflection; using System.Text; #endregion Namespaces. ////// Special visitor to serialize supported expression as query parameters /// in the generated URI. /// internal class ExpressionWriter : DataServiceALinqExpressionVisitor { #region Private fields. ///Internal buffer. private readonly StringBuilder builder; ///Data context used to generate type names for types. private readonly DataServiceContext context; ///Stack of expressions being visited. private readonly StackexpressionStack; /// set if can't translate expression private bool cantTranslateExpression; ///Parent expression of the current expression (expression.Peek()); possibly null. private Expression parent; #endregion Private fields. ////// Creates an ExpressionWriter for the specified /// Data context used to generate type names for types. private ExpressionWriter(DataServiceContext context) { Debug.Assert(context != null, "context != null"); this.context = context; this.builder = new StringBuilder(); this.expressionStack = new Stack. /// (); this.expressionStack.Push(null); } /// /// Serializes an expression to a string /// /// Data context used to generate type names for types. /// Expression to serialize ///serialized expression internal static string ExpressionToString(DataServiceContext context, Expression e) { ExpressionWriter ew = new ExpressionWriter(context); string serialized = ew.Translate(e); if (ew.cantTranslateExpression) { throw new NotSupportedException(Strings.ALinq_CantTranslateExpression(e.ToString())); } return serialized; } ///Main visit method. /// Expression to visit ///Visited expression internal override Expression Visit(Expression exp) { this.parent = this.expressionStack.Peek(); this.expressionStack.Push(exp); Expression result = base.Visit(exp); this.expressionStack.Pop(); return result; } ////// ConditionalExpression visit method /// /// The ConditionalExpression expression to visit ///The visited ConditionalExpression expression internal override Expression VisitConditional(ConditionalExpression c) { this.cantTranslateExpression = true; return c; } ////// LambdaExpression visit method /// /// The LambdaExpression to visit ///The visited LambdaExpression internal override Expression VisitLambda(LambdaExpression lambda) { this.cantTranslateExpression = true; return lambda; } ////// NewExpression visit method /// /// The NewExpression to visit ///The visited NewExpression internal override NewExpression VisitNew(NewExpression nex) { this.cantTranslateExpression = true; return nex; } ////// MemberInitExpression visit method /// /// The MemberInitExpression to visit ///The visited MemberInitExpression internal override Expression VisitMemberInit(MemberInitExpression init) { this.cantTranslateExpression = true; return init; } ////// ListInitExpression visit method /// /// The ListInitExpression to visit ///The visited ListInitExpression internal override Expression VisitListInit(ListInitExpression init) { this.cantTranslateExpression = true; return init; } ////// NewArrayExpression visit method /// /// The NewArrayExpression to visit ///The visited NewArrayExpression internal override Expression VisitNewArray(NewArrayExpression na) { this.cantTranslateExpression = true; return na; } ////// InvocationExpression visit method /// /// The InvocationExpression to visit ///The visited InvocationExpression internal override Expression VisitInvocation(InvocationExpression iv) { this.cantTranslateExpression = true; return iv; } ////// Input resource set references are intentionally omitted from the URL string. /// /// The input reference ///The same input reference expression internal override Expression VisitInputReferenceExpression(InputReferenceExpression ire) { // This method intentionally does not write anything to the URI. // This is how 'Where(.Id == 5)' becomes '$filter=Id eq 5'. Debug.Assert(ire != null, "ire != null"); if (this.parent == null || this.parent.NodeType != ExpressionType.MemberAccess) { // Ideally we refer to the parent expression as the un-translatable one, // because we cannot reference 'this' as a standalone expression; however // if the parent is null for any reasonn, we fall back to the expression itself. string expressionText = (this.parent != null) ? this.parent.ToString() : ire.ToString(); throw new NotSupportedException(Strings.ALinq_CantTranslateExpression(expressionText)); } return ire; } ////// MethodCallExpression visit method /// /// The MethodCallExpression expression to visit ///The visited MethodCallExpression expression internal override Expression VisitMethodCall(MethodCallExpression m) { string methodName; if (TypeSystem.TryGetQueryOptionMethod(m.Method, out methodName)) { this.builder.Append(methodName); this.builder.Append(UriHelper.LEFTPAREN); // There is a single function, 'substringof', which reorders its argument with // respect to the CLR method. Thus handling it as a special case rather than // using a more general argument reordering mechanism. if (methodName == "substringof") { Debug.Assert(m.Method.Name == "Contains", "m.Method.Name == 'Contains'"); Debug.Assert(m.Object != null, "m.Object != null"); Debug.Assert(m.Arguments.Count == 1, "m.Arguments.Count == 1"); this.Visit(m.Arguments[0]); this.builder.Append(UriHelper.COMMA); this.Visit(m.Object); } else { if (m.Object != null) { this.Visit(m.Object); } if (m.Arguments.Count > 0) { if (m.Object != null) { this.builder.Append(UriHelper.COMMA); } for (int ii = 0; ii < m.Arguments.Count; ii++) { this.Visit(m.Arguments[ii]); if (ii < m.Arguments.Count - 1) { this.builder.Append(UriHelper.COMMA); } } } } this.builder.Append(UriHelper.RIGHTPAREN); } else { this.cantTranslateExpression = true; } return m; } ////// Serializes an MemberExpression to a string /// /// Expression to serialize ///MemberExpression internal override Expression VisitMemberAccess(MemberExpression m) { if (m.Member is FieldInfo) { throw new NotSupportedException(Strings.ALinq_CantReferToPublicField(m.Member.Name)); } Expression e = this.Visit(m.Expression); // if this is a Nullableinstance, don't write out /Value since not supported by server if (m.Member.Name == "Value" && m.Member.DeclaringType.IsGenericType && m.Member.DeclaringType.GetGenericTypeDefinition() == typeof(Nullable<>)) { return m; } if (!IsInputReference(e)) { this.builder.Append(UriHelper.FORWARDSLASH); } this.builder.Append(m.Member.Name); return m; } /// /// ConstantExpression visit method /// /// The ConstantExpression expression to visit ///The visited ConstantExpression expression internal override Expression VisitConstant(ConstantExpression c) { string result = null; if (c.Value == null) { this.builder.Append(UriHelper.NULL); return c; } else if (!ClientConvert.TryKeyPrimitiveToString(c.Value, out result)) { throw new InvalidOperationException(Strings.ALinq_CouldNotConvert(c.Value)); } Debug.Assert(result != null, "result != null"); this.builder.Append(System.Uri.EscapeDataString(result)); return c; } ////// Serializes an UnaryExpression to a string /// /// Expression to serialize ///UnaryExpression internal override Expression VisitUnary(UnaryExpression u) { switch (u.NodeType) { case ExpressionType.Not: this.builder.Append(UriHelper.NOT); this.builder.Append(UriHelper.SPACE); this.VisitOperand(u.Operand); break; case ExpressionType.Negate: case ExpressionType.NegateChecked: this.builder.Append(UriHelper.SPACE); this.builder.Append(UriHelper.NEGATE); this.VisitOperand(u.Operand); break; case ExpressionType.Convert: case ExpressionType.ConvertChecked: if (u.Type != typeof(object)) { this.builder.Append(UriHelper.CAST); this.builder.Append(UriHelper.LEFTPAREN); if (!IsInputReference(u.Operand)) { this.Visit(u.Operand); this.builder.Append(UriHelper.COMMA); } this.builder.Append(UriHelper.QUOTE); this.builder.Append(this.TypeNameForUri(u.Type)); this.builder.Append(UriHelper.QUOTE); this.builder.Append(UriHelper.RIGHTPAREN); } else { if (!IsInputReference(u.Operand)) { this.Visit(u.Operand); } } break; case ExpressionType.UnaryPlus: // no-op always ignore. break; default: this.cantTranslateExpression = true; break; } return u; } ////// Serializes an BinaryExpression to a string /// /// BinaryExpression to serialize ///serialized expression internal override Expression VisitBinary(BinaryExpression b) { this.VisitOperand(b.Left); this.builder.Append(UriHelper.SPACE); switch (b.NodeType) { case ExpressionType.AndAlso: case ExpressionType.And: this.builder.Append(UriHelper.AND); break; case ExpressionType.OrElse: case ExpressionType.Or: this.builder.Append(UriHelper.OR); break; case ExpressionType.Equal: this.builder.Append(UriHelper.EQ); break; case ExpressionType.NotEqual: this.builder.Append(UriHelper.NE); break; case ExpressionType.LessThan: this.builder.Append(UriHelper.LT); break; case ExpressionType.LessThanOrEqual: this.builder.Append(UriHelper.LE); break; case ExpressionType.GreaterThan: this.builder.Append(UriHelper.GT); break; case ExpressionType.GreaterThanOrEqual: this.builder.Append(UriHelper.GE); break; case ExpressionType.Add: case ExpressionType.AddChecked: this.builder.Append(UriHelper.ADD); break; case ExpressionType.Subtract: case ExpressionType.SubtractChecked: this.builder.Append(UriHelper.SUB); break; case ExpressionType.Multiply: case ExpressionType.MultiplyChecked: this.builder.Append(UriHelper.MUL); break; case ExpressionType.Divide: this.builder.Append(UriHelper.DIV); break; case ExpressionType.Modulo: this.builder.Append(UriHelper.MOD); break; case ExpressionType.ArrayIndex: case ExpressionType.Power: case ExpressionType.Coalesce: case ExpressionType.ExclusiveOr: case ExpressionType.LeftShift: case ExpressionType.RightShift: default: this.cantTranslateExpression = true; break; } this.builder.Append(UriHelper.SPACE); this.VisitOperand(b.Right); return b; } ////// Serializes an TypeBinaryExpression to a string /// /// TypeBinaryExpression to serialize ///serialized expression internal override Expression VisitTypeIs(TypeBinaryExpression b) { this.builder.Append(UriHelper.ISOF); this.builder.Append(UriHelper.LEFTPAREN); if (!IsInputReference(b.Expression)) { this.Visit(b.Expression); this.builder.Append(UriHelper.COMMA); this.builder.Append(UriHelper.SPACE); } this.builder.Append(UriHelper.QUOTE); this.builder.Append(this.TypeNameForUri(b.TypeOperand)); this.builder.Append(UriHelper.QUOTE); this.builder.Append(UriHelper.RIGHTPAREN); return b; } ////// ParameterExpression visit method. /// /// The ParameterExpression expression to visit ///The visited ParameterExpression expression internal override Expression VisitParameter(ParameterExpression p) { return p; } ////// References to the current input - the resource set - do not appear in the URL. /// /// The expression to test ///private static bool IsInputReference(Expression exp) { return (exp is InputReferenceExpression || exp is ParameterExpression); } /// true if the expression represents a reference to the current (resource set) input; otherwisefalse .Gets the type name to be used in the URI for the given /// Type to get name for. ///. The name for the private string TypeNameForUri(Type type) { Debug.Assert(type != null, "type != null"); type = Nullable.GetUnderlyingType(type) ?? type; if (ClientConvert.IsKnownType(type)) { if (ClientConvert.IsSupportedPrimitiveTypeForUri(type)) { return ClientConvert.ToTypeName(type); } // unsupported primitive type throw new NotSupportedException(Strings.ALinq_CantCastToUnsupportedPrimitive(type.Name)); } else { return this.context.ResolveNameFromType(type) ?? type.FullName; } } ///, suitable for including in a URI. /// Visits operands for Binary and Unary expressions. /// Will only output parens if operand is complex expression, /// this is so don't have unecessary parens in URI. /// /// The operand expression to visit private void VisitOperand(Expression e) { if (e is BinaryExpression || e is UnaryExpression) { this.builder.Append(UriHelper.LEFTPAREN); this.Visit(e); this.builder.Append(UriHelper.RIGHTPAREN); } else { this.Visit(e); } } ////// Serializes an expression to a string /// /// Expression to serialize ///serialized expression private string Translate(Expression e) { this.Visit(e); return this.builder.ToString(); } } } // 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
- FillErrorEventArgs.cs
- PropertyMapper.cs
- TargetControlTypeAttribute.cs
- SemanticResultValue.cs
- ImageFormat.cs
- DataGridTextBox.cs
- __Filters.cs
- SBCSCodePageEncoding.cs
- Rotation3D.cs
- ApplyImportsAction.cs
- DataGridViewCellErrorTextNeededEventArgs.cs
- UpdatePanelTriggerCollection.cs
- ResourceReferenceExpressionConverter.cs
- TrackingMemoryStreamFactory.cs
- SQLInt16.cs
- ConsoleKeyInfo.cs
- LiteralTextContainerControlBuilder.cs
- dataprotectionpermission.cs
- UMPAttributes.cs
- AttributeCollection.cs
- InstallerTypeAttribute.cs
- ElementHostAutomationPeer.cs
- KeyboardEventArgs.cs
- ScrollBarRenderer.cs
- GridViewRowPresenterBase.cs
- ADMembershipProvider.cs
- DetailsViewModeEventArgs.cs
- TabControlCancelEvent.cs
- parserscommon.cs
- SessionStateSection.cs
- VectorValueSerializer.cs
- EtwProvider.cs
- FileCodeGroup.cs
- XmlSecureResolver.cs
- MarkupCompilePass2.cs
- ThreadExceptionDialog.cs
- SqlNamer.cs
- IsolationInterop.cs
- Int16Animation.cs
- XPathCompileException.cs
- NodeFunctions.cs
- Latin1Encoding.cs
- XPathNodeList.cs
- PassportAuthentication.cs
- mil_sdk_version.cs
- AutomationEvent.cs
- Canvas.cs
- Drawing.cs
- ACL.cs
- BypassElementCollection.cs
- NullableIntMinMaxAggregationOperator.cs
- DES.cs
- SrgsNameValueTag.cs
- ParagraphVisual.cs
- DataTemplateSelector.cs
- Attachment.cs
- SafeNativeMethods.cs
- UIPermission.cs
- ClientConfigurationHost.cs
- SettingsBindableAttribute.cs
- MapPathBasedVirtualPathProvider.cs
- CompareInfo.cs
- TypedTableBase.cs
- HMACMD5.cs
- HandlerFactoryCache.cs
- WindowsContainer.cs
- ResourceDictionary.cs
- SortExpressionBuilder.cs
- IndexerNameAttribute.cs
- PasswordBox.cs
- MemberPath.cs
- KnownColorTable.cs
- UnsafeNativeMethods.cs
- MediaCommands.cs
- EventLog.cs
- DropTarget.cs
- ScriptReference.cs
- SizeConverter.cs
- BindingExpressionUncommonField.cs
- ProfilePropertySettings.cs
- httpstaticobjectscollection.cs
- XmlMemberMapping.cs
- X509UI.cs
- DocumentPageView.cs
- RawUIStateInputReport.cs
- Graphics.cs
- Renderer.cs
- ConfigurationProperty.cs
- MarkerProperties.cs
- PersianCalendar.cs
- DragEventArgs.cs
- ExpressionConverter.cs
- ConstNode.cs
- KerberosSecurityTokenAuthenticator.cs
- StyleSelector.cs
- RSAOAEPKeyExchangeDeformatter.cs
- EventLogInternal.cs
- TdsValueSetter.cs
- RootBrowserWindow.cs
- QueryCursorEventArgs.cs