/// <summary> /// Gets the attributes associated with the specified member. /// </summary> /// <param name="memberInfo">The reflection member.</param> /// <param name="inherit">if set to <c>true</c> includes inherited attributes.</param> /// <returns>An enumeration of <see cref="Attribute"/>.</returns> public virtual List <Attribute> GetAttributes(MemberInfo memberInfo, bool inherit = true) { var key = new MemberInfoKey(memberInfo, inherit); lock (globalLock) { // Use a cache of attributes List <Attribute> attributes; if (cachedAttributes.TryGetValue(key, out attributes)) { return(attributes); } // Else retrieve all default attributes var defaultAttributes = Attribute.GetCustomAttributes(memberInfo, inherit); attributes = defaultAttributes.ToList(); // And add registered attributes List <Attribute> registered; if (registeredAttributes.TryGetValue(memberInfo, out registered)) { attributes.AddRange(registered); } // Add to the cache cachedAttributes.Add(key, attributes); return(attributes); } }
/// <summary> /// Gets the attributes associated with the specified member. /// </summary> /// <param name="memberInfo">The reflection member.</param> /// <param name="inherit">if set to <c>true</c> includes inherited attributes.</param> /// <returns>An enumeration of <see cref="Attribute"/>.</returns> public virtual IReadOnlyCollection <Attribute> GetAttributes(MemberInfo memberInfo, bool inherit = true) { var key = new MemberInfoKey(memberInfo, inherit); // Use a cache of attributes IReadOnlyCollection <Attribute> attributes; lock (cachedAttributes) { if (cachedAttributes.TryGetValue(key, out attributes)) { return(attributes); } // Else retrieve all default attributes var defaultAttributes = Attribute.GetCustomAttributes(memberInfo, inherit); var attributesToCache = defaultAttributes.ToList(); // And add registered attributes List <Attribute> registered; if (registeredAttributes.TryGetValue(memberInfo, out registered)) { attributesToCache.AddRange(registered); } attributes = attributesToCache.AsReadOnly(); // Add to the cache cachedAttributes.Add(key, attributes); } return(attributes); }
/// <summary> /// Gets the attributes associated with the specified member. /// </summary> /// <param name="memberInfo">The reflection member.</param> /// <param name="inherit">if set to <c>true</c> includes inherited attributes.</param> /// <returns>An enumeration of <see cref="Attribute"/>.</returns> public virtual List <Attribute> GetAttributes(MemberInfo memberInfo, bool inherit = true) { var key = new MemberInfoKey(memberInfo, inherit); // Use a cache of attributes List <Attribute> attributes; lock (lockObject) { if (cachedAttributes.TryGetValue(key, out attributes)) { return(attributes); } // Else retrieve all default attributes var defaultAttributes = Attribute.GetCustomAttributes(memberInfo, inherit); IEnumerable <Attribute> attributesToCache = defaultAttributes; // And add registered attributes List <Attribute> registered; if (registeredAttributes.TryGetValue(memberInfo, out registered)) { // Remove "real" attributes overridden by manually registered attributes attributesToCache = registered.Concat(defaultAttributes.Where(x => GetUsage(x).AllowMultiple || registered.All(y => y.GetType() != x.GetType()))); } attributes = attributesToCache.ToList(); // Add to the cache cachedAttributes.Add(key, attributes); } return(attributes); }
public static AttributeCollection GetRawAttributes(EventInfo eventInfo) { if (eventInfo == null) { throw new ArgumentNullException("eventInfo"); } string name = eventInfo.Name; Type declaringType = eventInfo.DeclaringType.UnderlyingSystemType; Type memberType = eventInfo.EventHandlerType.UnderlyingSystemType; MemberInfoKey memberInfoKey = new MemberInfoKey(name, declaringType.TypeHandle, memberType.TypeHandle); Dictionary <MemberInfoKey, AttributeCollection> attributesCache = DomainTypeDescriptor.EventInfoAttributesCache; AttributeCollection attributeCollection; if (!attributesCache.TryGetValue(memberInfoKey, out attributeCollection)) { lock (attributesCache) { if (!attributesCache.TryGetValue(memberInfoKey, out attributeCollection)) { attributesCache[memberInfoKey] = attributeCollection = TypeDescriptor.CreateEvent(declaringType, name, memberType, null).Attributes; } } } return(attributeCollection); }
public static AttributeCollection GetRawAttributes(PropertyInfo propertyInfo) { if (propertyInfo == null) { throw new ArgumentNullException("propertyInfo"); } string name = propertyInfo.Name; Type declaringType = propertyInfo.DeclaringType.UnderlyingSystemType; Type memberType = propertyInfo.PropertyType.UnderlyingSystemType; MemberInfoKey memberInfoKey = new MemberInfoKey(name, declaringType.TypeHandle, memberType.TypeHandle); Dictionary <MemberInfoKey, AttributeCollection> attributesCache = DomainTypeDescriptor.PropertyInfoAttributesCache; AttributeCollection attributeCollection; if (!attributesCache.TryGetValue(memberInfoKey, out attributeCollection) || attributeCollection == null) { lock (attributesCache) { // If there is an entry in the cache for this property, then the dependencies for it // have already been calculated previously. bool dependenciesAlreadyCalculated = attributesCache.TryGetValue(memberInfoKey, out attributeCollection); if (!dependenciesAlreadyCalculated || attributeCollection == null) { // This property either hasn't had its attributes retrieved, or one of the types on which // it is dependent has been refreshed since the attributes were last retrieved. Either way, // we need to recalculate the attributes for this property. attributesCache[memberInfoKey] = attributeCollection = TypeDescriptor.CreateProperty(declaringType, name, memberType, null).Attributes; if (!dependenciesAlreadyCalculated) { // Since we haven't calculated the dependencies of this property before, we need to do // so now so that we know what properties to update when the TypeDescriptor.Refreshed // event is raised. Dictionary <RuntimeTypeHandle, List <MemberInfoKey> > dependencies = DomainTypeDescriptor.PropertyTypeDependencies; while (memberType != null) { RuntimeTypeHandle memberTypeHandle = memberType.TypeHandle; List <MemberInfoKey> dependentProperties; if (!dependencies.TryGetValue(memberTypeHandle, out dependentProperties)) { dependencies[memberTypeHandle] = dependentProperties = new List <MemberInfoKey>(); } dependentProperties.Add(memberInfoKey); memberType = memberType.BaseType; } } } } } return(attributeCollection); }
public void CorrectlyMatchesInstanceMemberInfos() { Dictionary <MethodInfo, MemberInfoKey> instanceMethods = new Dictionary <MethodInfo, MemberInfoKey>() { { FindInstanceMethod(typeof(string), "ToLower"), new MemberInfoKey(typeof(string), "ToLower", true, true) }, { FindInstanceMethod(typeof(string), "ToLowerInvariant"), new MemberInfoKey(typeof(string), "ToLowerInvariant", true, true) }, { FindInstanceMethod(typeof(string), "ToUpper"), new MemberInfoKey(typeof(string), "ToUpper", true, true) }, { FindInstanceMethod(typeof(string), "ToUpperInvariant"), new MemberInfoKey(typeof(string), "ToUpperInvariant", true, true) }, { FindInstanceMethod(typeof(string), "Trim"), new MemberInfoKey(typeof(string), "Trim", true, true) }, { FindInstanceMethod(typeof(string), "StartsWith", typeof(string)), new MemberInfoKey(typeof(string), "StartsWith", true, true, typeof(string)) }, { FindInstanceMethod(typeof(string), "EndsWith", typeof(string)), new MemberInfoKey(typeof(string), "EndsWith", true, true, typeof(string)) }, { FindInstanceMethod(typeof(string), "IndexOf", typeof(string)), new MemberInfoKey(typeof(string), "IndexOf", true, true, typeof(string)) }, { FindInstanceMethod(typeof(string), "IndexOf", typeof(char)), new MemberInfoKey(typeof(string), "IndexOf", true, true, typeof(char)) }, { FindInstanceMethod(typeof(string), "Contains", typeof(string)), new MemberInfoKey(typeof(string), "Contains", true, true, typeof(string)) }, { FindInstanceMethod(typeof(string), "Replace", typeof(string), typeof(string)), new MemberInfoKey(typeof(string), "Replace", true, true, typeof(string), typeof(string)) }, { FindInstanceMethod(typeof(string), "Replace", typeof(char), typeof(char)), new MemberInfoKey(typeof(string), "Replace", true, true, typeof(char), typeof(char)) }, { FindInstanceMethod(typeof(string), "Substring", typeof(int)), new MemberInfoKey(typeof(string), "Substring", true, true, typeof(int)) }, { FindInstanceMethod(typeof(string), "Substring", typeof(int), typeof(int)), new MemberInfoKey(typeof(string), "Substring", true, true, typeof(int), typeof(int)) }, }; foreach (MethodInfo key in instanceMethods.Keys) { foreach (var pair in instanceMethods) { MemberInfoKey other = new MemberInfoKey(key); if (key == pair.Key) { Assert.IsTrue(pair.Value.Equals(other)); } else { Assert.IsFalse(pair.Value.Equals(other)); } } } }
/// <summary> /// Gets the attributes associated with the specified member. /// </summary> /// <param name="memberInfo">The reflection member.</param> /// <param name="inherit">if set to <c>true</c> includes inherited attributes.</param> /// <returns>An enumeration of <see cref="Attribute"/>.</returns> public virtual List <Attribute> GetAttributes(MemberInfo memberInfo, bool inherit = true) { var key = new MemberInfoKey(memberInfo, inherit); lock (globalLock) { // Use a cache of attributes List <Attribute> attributes; if (cachedAttributes.TryGetValue(key, out attributes)) { return(attributes); } // Else retrieve all default attributes var defaultAttributes = memberInfo.GetCustomAttributes(inherit).OfType <Attribute>(); attributes = defaultAttributes.ToList(); // And add registered attributes List <Attribute> registered; if (registeredAttributes.TryGetValue(memberInfo, out registered)) { attributes.AddRange(registered); } // Allow to remap attributes if (AttributeRemap != null) { for (int i = 0; i < attributes.Count; i++) { attributes[i] = AttributeRemap(attributes[i]); } } // Add to the cache cachedAttributes.Add(key, attributes); return(attributes); } }
public void CorrectlyMatchesPropertyInfos() { Dictionary <MemberInfo, MemberInfoKey> instanceProperties = new Dictionary <MemberInfo, MemberInfoKey>() { { FindInstanceProperty(typeof(string), "Length"), new MemberInfoKey(typeof(string), "Length", false, true) }, { FindInstanceProperty(typeof(DateTime), "Day"), new MemberInfoKey(typeof(DateTime), "Day", false, true) }, { FindInstanceProperty(typeof(DateTime), "Month"), new MemberInfoKey(typeof(DateTime), "Month", false, true) }, { FindInstanceProperty(typeof(DateTime), "Year"), new MemberInfoKey(typeof(DateTime), "Year", false, true) }, { FindInstanceProperty(typeof(DateTime), "Hour"), new MemberInfoKey(typeof(DateTime), "Hour", false, true) }, { FindInstanceProperty(typeof(DateTime), "Minute"), new MemberInfoKey(typeof(DateTime), "Minute", false, true) }, { FindInstanceProperty(typeof(DateTime), "Second"), new MemberInfoKey(typeof(DateTime), "Second", false, true) }, }; foreach (MemberInfo key in instanceProperties.Keys) { foreach (var pair in instanceProperties) { MemberInfoKey other = new MemberInfoKey(key); if (key == pair.Key) { Assert.IsTrue(pair.Value.Equals(other)); } else { Assert.IsFalse(pair.Value.Equals(other)); } } } }
public void CorrectlyMatchesStaticMemberInfos() { Dictionary <MethodInfo, MemberInfoKey> staticMethods = new Dictionary <MethodInfo, MemberInfoKey> { { FindStaticMethod(typeof(Math), "Floor", typeof(double)), new MemberInfoKey(typeof(Math), "Floor", true, false, typeof(double)) }, { FindStaticMethod(typeof(Math), "Ceiling", typeof(double)), new MemberInfoKey(typeof(Math), "Ceiling", true, false, typeof(double)) }, { FindStaticMethod(typeof(Math), "Round", typeof(double)), new MemberInfoKey(typeof(Math), "Round", true, false, typeof(double)) }, { FindStaticMethod(typeof(string), "Concat", typeof(string), typeof(string)), new MemberInfoKey(typeof(string), "Concat", true, false, typeof(string), typeof(string)) } }; // Windows 8 supports decimal.Floor(), decimal.Ceiling() and decimal.Round(), but Windows Phone does not, // so we have to ensure these method infos exist before we add them. MethodInfo possibleFloorMethod = FindStaticMethod(typeof(Decimal), "Floor", typeof(decimal)); if (possibleFloorMethod != null) { staticMethods.Add(possibleFloorMethod, new MemberInfoKey(typeof(Decimal), "Floor", true, false, typeof(decimal))); } MethodInfo possibleCeilingMethod = FindStaticMethod(typeof(Decimal), "Ceiling", typeof(decimal)); if (possibleCeilingMethod != null) { staticMethods.Add(possibleCeilingMethod, new MemberInfoKey(typeof(Decimal), "Ceiling", true, false, typeof(decimal))); } MethodInfo possibleRoundMethod = FindStaticMethod(typeof(Decimal), "Round", typeof(decimal)); if (possibleRoundMethod != null) { staticMethods.Add(possibleRoundMethod, new MemberInfoKey(typeof(Decimal), "Round", true, false, typeof(decimal))); } // Windows Phone 7.5 does not support Math.Floor(), Math.Round() and Math.Ceiling() for decimals MethodInfo possibleCeilingMethodMath = FindStaticMethod(typeof(Math), "Ceiling", typeof(decimal)); if (possibleCeilingMethodMath != null) { staticMethods.Add(possibleCeilingMethodMath, new MemberInfoKey(typeof(Math), "Ceiling", true, false, typeof(decimal))); } MethodInfo possibleFloorMethodMath = FindStaticMethod(typeof(Math), "Floor", typeof(decimal)); if (possibleFloorMethodMath != null) { staticMethods.Add(possibleFloorMethodMath, new MemberInfoKey(typeof(Math), "Floor", true, false, typeof(decimal))); } MethodInfo possibleRoundMethodMath = FindStaticMethod(typeof(Math), "Round", typeof(decimal)); if (possibleRoundMethodMath != null) { staticMethods.Add(possibleRoundMethodMath, new MemberInfoKey(typeof(Math), "Round", true, false, typeof(decimal))); } foreach (MethodInfo key in staticMethods.Keys) { foreach (var pair in staticMethods) { MemberInfoKey other = new MemberInfoKey(key); if (key == pair.Key) { Assert.IsTrue(pair.Value.Equals(other)); } else { Assert.IsFalse(pair.Value.Equals(other)); } } } }
/// <summary> /// Process method calls and translate them into OData. /// </summary> /// <param name="expression"> /// The expression to visit. /// </param> /// <returns> /// The visited expression. /// </returns> private Expression VisitMethodCall(MethodCallExpression expression) { // Look for either an instance or static method string methodName = null; MemberInfoKey methodInfoKey = new MemberInfoKey(expression.Method); if (InstanceMethods.TryGetValue(methodInfoKey, out methodName)) { this.VisitODataMethodCall(expression, methodName, false); } else if (StaticMethods.TryGetValue(methodInfoKey, out methodName)) { this.VisitODataMethodCall(expression, methodName, true); } else if (expression.Method.GetBaseDefinition().Equals(toStringMethod)) { // handle the ToString method here // toString will only occur on expression that rely on a parameter, // because otherwise the partial evaluator would have already evaluated it // we get the base definition to detect overrides of ToString, which are pretty common this.Visit(expression.Object); } else { this.VisitCustomMethodCall(expression); } return expression; }
/// <summary> /// Process member references. /// </summary> /// <param name="expression"> /// The expression to visit. /// </param> /// <returns> /// The visited expression. /// </returns> private Expression VisitMemberAccess(MemberExpression expression) { // Lookup the Mobile Services name of the member and use that string memberName = GetTableMemberName(expression, this.contractResolver); if (memberName != null) { this.filter.Append(memberName); return expression; } // Check if this member is actually a function that looks like a // property (like string.Length, etc.) string methodName = null; MemberInfoKey memberInfoKey = new MemberInfoKey(expression.Member); if (InstanceProperties.TryGetValue(memberInfoKey, out methodName)) { this.filter.Append(methodName); this.filter.Append("("); this.Visit(expression.Expression); this.filter.Append(")"); return expression; } // Otherwise we can't process the member. throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, Resources.FilterBuildingExpressionVisitor_MemberUnsupported, expression != null && expression.Member != null ? expression.Member.Name : null, expression != null ? expression.ToString() : null)); }
public void CorrectlyMatchesInstanceMemberInfos() { Dictionary<MethodInfo, MemberInfoKey> instanceMethods = new Dictionary<MethodInfo, MemberInfoKey>() { { FindInstanceMethod(typeof(string), "ToLower"), new MemberInfoKey(typeof(string), "ToLower", true, true) }, { FindInstanceMethod(typeof(string), "ToLowerInvariant"), new MemberInfoKey(typeof(string), "ToLowerInvariant", true, true) }, { FindInstanceMethod(typeof(string), "ToUpper"), new MemberInfoKey(typeof(string), "ToUpper", true, true) }, { FindInstanceMethod(typeof(string), "ToUpperInvariant"), new MemberInfoKey(typeof(string), "ToUpperInvariant", true, true) }, { FindInstanceMethod(typeof(string), "Trim"), new MemberInfoKey(typeof(string), "Trim", true, true) }, { FindInstanceMethod(typeof(string), "StartsWith", typeof(string)), new MemberInfoKey(typeof(string), "StartsWith", true, true, typeof(string)) }, { FindInstanceMethod(typeof(string), "EndsWith", typeof(string)), new MemberInfoKey(typeof(string), "EndsWith", true, true, typeof(string)) }, { FindInstanceMethod(typeof(string), "IndexOf", typeof(string)), new MemberInfoKey(typeof(string), "IndexOf", true, true, typeof(string)) }, { FindInstanceMethod(typeof(string), "IndexOf", typeof(char)), new MemberInfoKey(typeof(string), "IndexOf", true, true, typeof(char)) }, { FindInstanceMethod(typeof(string), "Contains", typeof(string)), new MemberInfoKey(typeof(string), "Contains", true, true, typeof(string)) }, { FindInstanceMethod(typeof(string), "Replace", typeof(string), typeof(string)), new MemberInfoKey(typeof(string), "Replace", true, true, typeof(string), typeof(string)) }, { FindInstanceMethod(typeof(string), "Replace", typeof(char), typeof(char)), new MemberInfoKey(typeof(string), "Replace", true, true, typeof(char), typeof(char)) }, { FindInstanceMethod(typeof(string), "Substring", typeof(int)), new MemberInfoKey(typeof(string), "Substring", true, true, typeof(int)) }, { FindInstanceMethod(typeof(string), "Substring", typeof(int), typeof(int)), new MemberInfoKey(typeof(string), "Substring", true, true, typeof(int), typeof(int)) }, }; foreach (MethodInfo key in instanceMethods.Keys) { foreach (var pair in instanceMethods) { MemberInfoKey other = new MemberInfoKey(key); if (key == pair.Key) { Assert.IsTrue(pair.Value.Equals(other)); } else { Assert.IsFalse(pair.Value.Equals(other)); } } } }
public void CorrectlyMatchesPropertyInfos() { Dictionary<MemberInfo, MemberInfoKey> instanceProperties = new Dictionary<MemberInfo, MemberInfoKey>() { { FindInstanceProperty(typeof(string), "Length"), new MemberInfoKey(typeof(string), "Length", false, true) }, { FindInstanceProperty(typeof(DateTime), "Day"), new MemberInfoKey(typeof(DateTime), "Day", false, true) }, { FindInstanceProperty(typeof(DateTime), "Month"), new MemberInfoKey(typeof(DateTime), "Month", false, true) }, { FindInstanceProperty(typeof(DateTime), "Year"), new MemberInfoKey(typeof(DateTime), "Year", false, true) }, { FindInstanceProperty(typeof(DateTime), "Hour"), new MemberInfoKey(typeof(DateTime), "Hour", false, true) }, { FindInstanceProperty(typeof(DateTime), "Minute"), new MemberInfoKey(typeof(DateTime), "Minute", false, true) }, { FindInstanceProperty(typeof(DateTime), "Second"), new MemberInfoKey(typeof(DateTime), "Second", false, true) }, }; foreach (MemberInfo key in instanceProperties.Keys) { foreach (var pair in instanceProperties) { MemberInfoKey other = new MemberInfoKey(key); if (key == pair.Key) { Assert.IsTrue(pair.Value.Equals(other)); } else { Assert.IsFalse(pair.Value.Equals(other)); } } } }
public void CorrectlyMatchesStaticMemberInfos() { Dictionary<MethodInfo, MemberInfoKey> staticMethods = new Dictionary<MethodInfo, MemberInfoKey> { { FindStaticMethod(typeof(Math), "Floor", typeof(double)), new MemberInfoKey(typeof(Math), "Floor", true, false, typeof(double)) }, { FindStaticMethod(typeof(Math), "Ceiling", typeof(double)), new MemberInfoKey(typeof(Math), "Ceiling", true, false, typeof(double)) }, { FindStaticMethod(typeof(Math), "Round", typeof(double)), new MemberInfoKey(typeof(Math), "Round", true, false, typeof(double)) }, { FindStaticMethod(typeof(string), "Concat", typeof(string), typeof(string)), new MemberInfoKey(typeof(string), "Concat", true, false, typeof(string), typeof(string)) } }; // Windows 8 supports decimal.Floor(), decimal.Ceiling() and decimal.Round(), but Windows Phone does not, // so we have to ensure these method infos exist before we add them. MethodInfo possibleFloorMethod = FindStaticMethod(typeof(Decimal), "Floor", typeof(decimal)); if (possibleFloorMethod != null) { staticMethods.Add(possibleFloorMethod, new MemberInfoKey(typeof(Decimal), "Floor", true, false, typeof(decimal))); } MethodInfo possibleCeilingMethod = FindStaticMethod(typeof(Decimal), "Ceiling", typeof(decimal)); if (possibleCeilingMethod != null) { staticMethods.Add(possibleCeilingMethod, new MemberInfoKey(typeof(Decimal), "Ceiling", true, false, typeof(decimal))); } MethodInfo possibleRoundMethod = FindStaticMethod(typeof(Decimal), "Round", typeof(decimal)); if (possibleRoundMethod != null) { staticMethods.Add(possibleRoundMethod, new MemberInfoKey(typeof(Decimal), "Round", true, false, typeof(decimal))); } // Windows Phone 7.5 does not support Math.Floor(), Math.Round() and Math.Ceiling() for decimals MethodInfo possibleCeilingMethodMath = FindStaticMethod(typeof(Math), "Ceiling", typeof(decimal)); if (possibleCeilingMethodMath != null) { staticMethods.Add(possibleCeilingMethodMath, new MemberInfoKey(typeof(Math), "Ceiling", true, false, typeof(decimal))); } MethodInfo possibleFloorMethodMath = FindStaticMethod(typeof(Math), "Floor", typeof(decimal)); if (possibleFloorMethodMath != null) { staticMethods.Add(possibleFloorMethodMath, new MemberInfoKey(typeof(Math), "Floor", true, false, typeof(decimal))); } MethodInfo possibleRoundMethodMath = FindStaticMethod(typeof(Math), "Round", typeof(decimal)); if (possibleRoundMethodMath != null) { staticMethods.Add(possibleRoundMethodMath, new MemberInfoKey(typeof(Math), "Round", true, false, typeof(decimal))); } foreach (MethodInfo key in staticMethods.Keys) { foreach (var pair in staticMethods) { MemberInfoKey other = new MemberInfoKey(key); if (key == pair.Key) { Assert.IsTrue(pair.Value.Equals(other)); } else { Assert.IsFalse(pair.Value.Equals(other)); } } } }
/// <summary> /// Process member references. /// </summary> /// <param name="expression"> /// The expression to visit. /// </param> /// <returns> /// The visited expression. /// </returns> private Expression VisitMemberAccess(MemberExpression expression) { // Lookup the Mobile Services name of the member and use that string memberName = GetTableMemberName(expression, this.contractResolver); if (memberName != null) { this.filterExpression.Push(new MemberAccessNode(null, memberName)); return expression; } // Check if this member is actually a function that looks like a // property (like string.Length, etc.) string methodName = null; MemberInfoKey memberInfoKey = new MemberInfoKey(expression.Member); if (InstanceProperties.TryGetValue(memberInfoKey, out methodName)) { var fnCallNode = new FunctionCallNode(methodName, null); this.filterExpression.Push(fnCallNode); this.Visit(expression.Expression); this.SetChildren(fnCallNode); return expression; } // Otherwise we can't process the member. throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, "The member '{0}' is not supported in the 'Where' Mobile Services query expression '{1}'.", expression != null && expression.Member != null ? expression.Member.Name : null, expression != null ? expression.ToString() : null)); }