Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / ClientType.cs / 4 / ClientType.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// type resolver
//
//---------------------------------------------------------------------
namespace System.Data.Services.Client
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Data.Services.Common;
using System.Linq;
///
/// wrapper around a clr type to
/// get/set properties
/// add items to collections
/// support open types
///
[DebuggerDisplay("{ElementTypeName}")]
internal sealed class ClientType
{
/// what is the clr full name using ToString for generic name expansion
internal readonly string ElementTypeName;
/// what clr type does this represent
internal readonly Type ElementType;
/// if HasKeys then EntityType else if !KnownType then ComplexType else PrimitiveType
internal readonly bool HasKeys;
/// count of keys on entity type
internal readonly int KeyCount;
#region static fields
/// appdomain cache discovered types with properties that we materialize
private static readonly Dictionary types = new Dictionary();
/// cache <T> and wireName to mapped type
private static readonly Dictionary namedTypes = new Dictionary(new TypeNameEqualityComparer());
#endregion
#if ASTORIA_OPEN_OBJECT
/// IDictionary<string,object> OpenProperites { get; }
private readonly ClientProperty openProperties;
#endif
/// properties
private ArraySet properties;
/// Property that holds data for ATOM-style media link entries
private ClientProperty mediaDataMember;
///
/// discover and prepare properties for usage
///
/// type being processed
/// parameter name
/// Whether the skip the check for settable properties.
private ClientType(Type type, string typeName, bool skipSettableCheck)
{
Debug.Assert(null != type, "null type");
Debug.Assert(!String.IsNullOrEmpty(typeName), "empty typeName");
this.ElementTypeName = typeName;
this.ElementType = Nullable.GetUnderlyingType(type) ?? type;
#if ASTORIA_OPEN_OBJECT
string openObjectPropertyName = null;
#endif
if (!ClientConvert.IsKnownType(this.ElementType))
{
#if ASTORIA_OPEN_OBJECT
#region OpenObject determined by walking type hierarchy and looking for [OpenObjectAttribute("PropertyName")]
Type openObjectDeclared = this.ElementType;
for (Type tmp = openObjectDeclared; (null != tmp) && (typeof(object) != tmp); tmp = tmp.BaseType)
{
object[] attributes = openObjectDeclared.GetCustomAttributes(typeof(OpenObjectAttribute), false);
if (1 == attributes.Length)
{
if (null != openObjectPropertyName)
{
throw Error.InvalidOperation(Strings.Clienttype_MultipleOpenProperty(this.ElementTypeName));
}
openObjectPropertyName = ((OpenObjectAttribute)attributes[0]).OpenObjectPropertyName;
openObjectDeclared = tmp;
}
}
#endregion
#endif
Type keyPropertyDeclaredType = null;
DataServiceKeyAttribute dska = type.GetCustomAttributes(true).OfType().FirstOrDefault();
foreach (PropertyInfo pinfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
//// examples where class
//// the normal examples
//// PropertyType Property { get; set }
//// Nullable Property { get; set; }
//// if 'Property: struct' then we would be unable set the property during construction (and have them stick)
//// but when its a class, we can navigate if non-null and set the nested properties
//// PropertyType Property { get; } where PropertyType: class
//// we do support adding elements to collections
//// ICollection { get; /*ignored set;*/ }
//// indexed properties are not suported because
//// we don't have anything to use as the index
//// PropertyType Property[object x] { /*ignored get;*/ /*ignored set;*/ }
//// also ignored
//// if PropertyType.IsPointer (like byte*)
//// if PropertyType.IsArray except for byte[] and char[]
//// if PropertyType == IntPtr or UIntPtr
Type ptype = pinfo.PropertyType; // class / interface / value
ptype = Nullable.GetUnderlyingType(ptype) ?? ptype;
if (ptype.IsPointer ||
(ptype.IsArray && (typeof(byte[]) != ptype) && typeof(char[]) != ptype) ||
(typeof(IntPtr) == ptype) ||
(typeof(UIntPtr) == ptype))
{
continue;
}
Debug.Assert(!ptype.ContainsGenericParameters, "remove when test case is found that encounters this");
if (pinfo.CanRead &&
(!ptype.IsValueType || pinfo.CanWrite) &&
!ptype.ContainsGenericParameters &&
(0 == pinfo.GetIndexParameters().Length))
{
#region IsKey?
bool keyProperty = dska != null ? dska.KeyNames.Contains(pinfo.Name) : false;
if (keyProperty)
{
if (null == keyPropertyDeclaredType)
{
keyPropertyDeclaredType = pinfo.DeclaringType;
}
else if (keyPropertyDeclaredType != pinfo.DeclaringType)
{
throw Error.InvalidOperation(Strings.ClientType_KeysOnDifferentDeclaredType(this.ElementTypeName));
}
if (!ClientConvert.IsKnownType(ptype))
{
throw Error.InvalidOperation(Strings.ClientType_KeysMustBeSimpleTypes(this.ElementTypeName));
}
this.KeyCount++;
}
#endregion
#if ASTORIA_OPEN_OBJECT
#region IsOpenObjectProperty?
bool openProperty = (openObjectPropertyName == pinfo.Name) &&
typeof(IDictionary).IsAssignableFrom(ptype);
Debug.Assert(keyProperty != openProperty || (!keyProperty && !openProperty), "key can't be open type");
#endregion
ClientProperty property = new ClientProperty(pinfo, ptype, keyProperty, openProperty);
if (!property.OpenObjectProperty)
#else
ClientProperty property = new ClientProperty(pinfo, ptype, keyProperty);
#endif
{
if (!this.properties.Add(property, ClientProperty.NameEquality))
{
// 2nd property with same name shadows another property
int shadow = this.IndexOfProperty(property.PropertyName);
if (!property.DeclaringType.IsAssignableFrom(this.properties[shadow].DeclaringType))
{ // the new property is on the most derived class
this.properties.RemoveAt(shadow);
this.properties.Add(property, null);
}
}
}
#if ASTORIA_OPEN_OBJECT
else
{
if (pinfo.DeclaringType == openObjectDeclared)
{
this.openProperties = property;
}
}
#endif
}
}
#region No KeyAttribute, discover key by name pattern { DeclaringType.Name+ID, ID }
if (null == keyPropertyDeclaredType)
{
ClientProperty key = null;
for (int i = this.properties.Count - 1; 0 <= i; --i)
{
string propertyName = this.properties[i].PropertyName;
if (propertyName.EndsWith("ID", StringComparison.Ordinal))
{
string declaringTypeName = this.properties[i].DeclaringType.Name;
if ((propertyName.Length == (declaringTypeName.Length + 2)) &&
propertyName.StartsWith(declaringTypeName, StringComparison.Ordinal))
{
// matched "DeclaringType.Name+ID" pattern
if ((null == keyPropertyDeclaredType) ||
this.properties[i].DeclaringType.IsAssignableFrom(keyPropertyDeclaredType))
{
keyPropertyDeclaredType = this.properties[i].DeclaringType;
key = this.properties[i];
}
}
else if ((null == keyPropertyDeclaredType) && (2 == propertyName.Length))
{
// matched "ID" pattern
keyPropertyDeclaredType = this.properties[i].DeclaringType;
key = this.properties[i];
}
}
}
if (null != key)
{
Debug.Assert(0 == this.KeyCount, "shouldn't have a key yet");
key.KeyProperty = true;
this.KeyCount++;
}
}
else if (this.KeyCount != dska.KeyNames.Count)
{
var m = (from string a in dska.KeyNames
where null == (from b in this.properties
where b.PropertyName == a
select b).FirstOrDefault()
select a).First();
throw Error.InvalidOperation(Strings.ClientType_MissingProperty(this.ElementTypeName, m));
}
#endregion
this.HasKeys = (null != keyPropertyDeclaredType);
Debug.Assert(this.KeyCount == this.Properties.Where(k => k.KeyProperty).Count(), "KeyCount mismatch");
this.WireUpMimeTypeProperties();
this.CheckMediaLinkEntry();
if (!skipSettableCheck)
{
#if ASTORIA_OPEN_OBJECT
if ((0 == this.properties.Count) && (null == this.openProperties))
#else
if (0 == this.properties.Count)
#endif
{ // implicit construction?
throw Error.InvalidOperation(Strings.ClientType_NoSettableFields(this.ElementTypeName));
}
}
}
this.properties.Sort(ClientProperty.GetPropertyName, String.CompareOrdinal);
#if ASTORIA_OPEN_OBJECT
#region Validate OpenObjectAttribute was used
if ((null != openObjectPropertyName) && (null == this.openProperties))
{
throw Error.InvalidOperation(Strings.ClientType_MissingOpenProperty(this.ElementTypeName, openObjectPropertyName));
}
Debug.Assert((null != openObjectPropertyName) == (null != this.openProperties), "OpenProperties mismatch");
#endregion
#endif
}
/// Properties sorted by name
internal ArraySet Properties
{
get { return this.properties; }
}
/// Property that holds data for ATOM-style media link entries
internal ClientProperty MediaDataMember
{
get { return this.mediaDataMember; }
}
///
/// get a client type resolver
///
/// type to wrap
/// client type
internal static ClientType Create(Type type)
{
return Create(type, true /* expectModelType */);
}
///
/// get a client type resolver
///
/// type to wrap
/// Whether the type is expected to be a model type.
/// client type
internal static ClientType Create(Type type, bool expectModelType)
{
ClientType clientType;
lock (ClientType.types)
{
ClientType.types.TryGetValue(type, out clientType);
}
if (null == clientType)
{
bool skipSettableCheck = !expectModelType;
clientType = new ClientType(type, type.ToString(), skipSettableCheck); // ToString expands generic type name where as FullName does not
if (expectModelType)
{
lock (ClientType.types)
{
ClientType existing;
if (ClientType.types.TryGetValue(type, out existing))
{
clientType = existing;
}
else
{
ClientType.types.Add(type, clientType);
}
}
}
}
return clientType;
}
#if !ASTORIA_LIGHT
///
/// resolve the wireName/userType pair to a CLR type
///
/// type name sent by server
/// type passed by user or on propertyType from a class
/// mapped clr type
internal static Type ResolveFromName(string wireName, Type userType)
#else
///
/// resolve the wireName/userType pair to a CLR type
///
/// type name sent by server
/// type passed by user or on propertyType from a class
/// typeof context for strongly typed assembly
/// mapped clr type
internal static Type ResolveFromName(string wireName, Type userType, Type contextType)
#endif
{
Type foundType;
TypeName typename;
typename.Type = userType;
typename.Name = wireName;
lock (ClientType.namedTypes)
{
ClientType.namedTypes.TryGetValue(typename, out foundType);
}
if (null == foundType)
{
string name = wireName;
int index = wireName.LastIndexOf('.');
if ((0 <= index) && (index < wireName.Length - 1))
{
name = wireName.Substring(index + 1);
}
if (userType.Name == name)
{
foundType = userType;
}
else
{
#if !ASTORIA_LIGHT
// searching only loaded assemblies, not referenced assemblies
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
#else
foreach (Assembly assembly in new Assembly[] { userType.Assembly, contextType.Assembly }.Distinct())
#endif
{
Type found = assembly.GetType(wireName, false);
ResolveSubclass(name, userType, found, ref foundType);
if (null == found)
{
Type[] types = null;
try
{
types = assembly.GetTypes();
}
catch (ReflectionTypeLoadException)
{
}
if (null != types)
{
foreach (Type t in types)
{
ResolveSubclass(name, userType, t, ref foundType);
}
}
}
}
}
if (null != foundType)
{
lock (ClientType.namedTypes)
{
ClientType.namedTypes[typename] = foundType;
}
}
}
return foundType;
}
///
/// get concrete type that implements the genericTypeDefinitation
///
/// starting type
/// the generic type definition to find
/// concrete type that implementats the generic type
internal static Type GetImplementationType(Type propertyType, Type genericTypeDefinition)
{
if (IsConstructedGeneric(propertyType, genericTypeDefinition))
{ // propertyType is ICollection
return propertyType;
}
else
{
Type implementationType = null;
foreach (Type interfaceType in propertyType.GetInterfaces())
{
if (IsConstructedGeneric(interfaceType, genericTypeDefinition))
{
if (null == implementationType)
{ // found implmentation of ICollection
implementationType = interfaceType;
}
else
{ // ICollection and ICollection
throw Error.NotSupported(Strings.ClientType_MultipleImplementationNotSupported);
}
}
}
return implementationType;
}
}
///
/// get element type, resolves ICollection and Nullable
///
/// starting type
/// the generic type definition to find
/// the method to search for
/// the collection type if found
/// element types
internal static MethodInfo GetCollectionMethod(Type propertyType, Type genericTypeDefinition, string methodName, out Type type)
{
Debug.Assert(null != propertyType, "null propertyType");
Debug.Assert(null != genericTypeDefinition, "null genericTypeDefinition");
Debug.Assert(genericTypeDefinition.IsGenericTypeDefinition, "!IsGenericTypeDefinition");
type = null;
Type implementationType = GetImplementationType(propertyType, genericTypeDefinition);
if (null != implementationType)
{
Type[] genericArguments = implementationType.GetGenericArguments();
MethodInfo methodInfo = implementationType.GetMethod(methodName);
Debug.Assert(null != methodInfo, "should have found the method");
#if DEBUG
Debug.Assert(null != genericArguments, "null genericArguments");
ParameterInfo[] parameters = methodInfo.GetParameters();
if (0 < parameters.Length)
{
// following assert was disabled for Contains which returns bool
// Debug.Assert(typeof(void) == methodInfo.ReturnParameter.ParameterType, "method doesn't return void");
Debug.Assert(genericArguments.Length == parameters.Length, "genericArguments don't match parameters");
for (int i = 0; i < genericArguments.Length; ++i)
{
Debug.Assert(genericArguments[i] == parameters[i].ParameterType, "parameter doesn't match generic argument");
}
}
#endif
type = genericArguments[genericArguments.Length - 1];
return methodInfo;
}
return null;
}
///
/// create object using default constructor
///
/// instance of propertyType
internal object CreateInstance()
{
return Activator.CreateInstance(this.ElementType);
}
///
/// get property wrapper for a property name, might be method around open types for otherwise unknown properties
///
/// property name
/// are missing properties ignored
/// property wrapper
/// for unknown properties on closed types
internal ClientProperty GetProperty(string propertyName, bool ignoreMissingProperties)
{
int index = this.IndexOfProperty(propertyName);
if (0 <= index)
{
return this.properties[index];
}
#if ASTORIA_OPEN_OBJECT
else if (null != this.openProperties)
{
return this.openProperties;
}
#endif
else if (!ignoreMissingProperties)
{
throw Error.InvalidOperation(Strings.ClientType_MissingProperty(this.ElementTypeName, propertyName));
}
return null;
}
///
/// Checks whether the specified is a
/// closed constructed type of the generic type.
///
/// Type to check.
/// Generic type for checkin.
/// true if is a constructed type of .
/// The check is an immediate check; no inheritance rules are applied.
private static bool IsConstructedGeneric(Type type, Type genericTypeDefinition)
{
Debug.Assert(type != null, "type != null");
Debug.Assert(!type.ContainsGenericParameters, "remove when test case is found that encounters this");
Debug.Assert(genericTypeDefinition != null, "genericTypeDefinition != null");
return type.IsGenericType && (type.GetGenericTypeDefinition() == genericTypeDefinition) && !type.ContainsGenericParameters;
}
///
/// is the type a visible subclass with correct name
///
/// type name from server
/// the type from user for materialization or property type
/// type being tested
/// the previously discovered matching type
/// if the mapping is ambiguous
private static void ResolveSubclass(string wireClassName, Type userType, Type type, ref Type existing)
{
if ((null != type) && type.IsVisible && (wireClassName == type.Name) && userType.IsAssignableFrom(type))
{
if (null != existing)
{
throw Error.InvalidOperation(Strings.Deserialize_Current(existing, type));
}
existing = type;
}
}
/// get the index of a property
/// propertyName
/// index else -1
private int IndexOfProperty(string propertyName)
{
return this.properties.IndexOf(propertyName, ClientProperty.GetPropertyName, String.Equals);
}
///
/// Find properties with dynamic MIME type related properties and
/// set the references from each ClientProperty to its related MIME type property
///
private void WireUpMimeTypeProperties()
{
MimeTypePropertyAttribute attribute = (MimeTypePropertyAttribute)this.ElementType.GetCustomAttributes(typeof(MimeTypePropertyAttribute), true).SingleOrDefault();
if (null != attribute)
{
int dataIndex, mimeTypeIndex;
if ((0 > (dataIndex = this.IndexOfProperty(attribute.DataPropertyName))) ||
(0 > (mimeTypeIndex = this.IndexOfProperty(attribute.MimeTypePropertyName))))
{
throw Error.InvalidOperation(Strings.ClientType_MissingMimeTypeProperty(attribute.DataPropertyName, attribute.MimeTypePropertyName));
}
Debug.Assert(0 <= dataIndex, "missing data property");
Debug.Assert(0 <= mimeTypeIndex, "missing mime type property");
this.Properties[dataIndex].MimeTypeProperty = this.Properties[mimeTypeIndex];
}
}
///
/// Check if this type represents an ATOM-style media link entry and
/// if so mark the ClientType as such
///
private void CheckMediaLinkEntry()
{
object[] attributes = this.ElementType.GetCustomAttributes(typeof(MediaEntryAttribute), true);
if (attributes != null && attributes.Length > 0)
{
Debug.Assert(attributes.Length == 1, "The AttributeUsage in the attribute definition should be presenting more than 1 per property");
int index = this.IndexOfProperty(((MediaEntryAttribute)attributes[0]).MediaMemberName);
if (index < 0)
{
throw Error.InvalidOperation(Strings.ClientType_MissingMediaEntryProperty(
((MediaEntryAttribute)attributes[0]).MediaMemberName));
}
this.mediaDataMember = this.properties[index];
}
}
/// type + wireName combination
private struct TypeName
{
/// type
internal Type Type;
/// type name from server
internal string Name;
}
///
/// wrapper around property methods
///
[DebuggerDisplay("{PropertyName}")]
internal sealed class ClientProperty
{
/// property name for debugging
internal readonly string PropertyName;
/// type of the property
internal readonly Type NullablePropertyType;
/// type of the property
internal readonly Type PropertyType;
/// what is the nested collection element
internal readonly Type CollectionType;
///
/// Is this a known primitive/reference type or an entity/complex/collection type?
///
internal readonly bool IsKnownType;
#if ASTORIA_OPEN_OBJECT
/// IDictionary<string,object> OpenProperites { get; }
internal readonly bool OpenObjectProperty;
#endif
/// property getter
private readonly MethodInfo propertyGetter;
/// property setter
private readonly MethodInfo propertySetter;
/// "set_Item" method supporting IDictionary properties
private readonly MethodInfo setMethod;
/// "Add" method supporting ICollection<> properties
private readonly MethodInfo addMethod;
/// "Remove" method supporting ICollection<> properties
private readonly MethodInfo removeMethod;
/// "Contains" method support ICollection<> properties
private readonly MethodInfo containsMethod;
/// IsKeyProperty?
private bool keyProperty;
/// The other property in this type that holds the MIME type for this one
private ClientProperty mimeTypeProperty;
///
/// constructor
///
/// property
/// propertyType
/// keyProperty
#if ASTORIA_OPEN_OBJECT
/// openObjectProperty
internal ClientProperty(PropertyInfo property, Type propertyType, bool keyProperty, bool openObjectProperty)
#else
internal ClientProperty(PropertyInfo property, Type propertyType, bool keyProperty)
#endif
{
Debug.Assert(null != property, "null property");
Debug.Assert(null != propertyType, "null propertyType");
Debug.Assert(null == Nullable.GetUnderlyingType(propertyType), "should already have been denullified");
this.PropertyName = property.Name;
this.NullablePropertyType = property.PropertyType;
this.PropertyType = propertyType;
this.propertyGetter = property.GetGetMethod();
this.propertySetter = property.GetSetMethod();
this.keyProperty = keyProperty;
#if ASTORIA_OPEN_OBJECT
this.OpenObjectProperty = openObjectProperty;
#endif
this.IsKnownType = ClientConvert.IsKnownType(propertyType);
if (!this.IsKnownType)
{
this.setMethod = GetCollectionMethod(this.PropertyType, typeof(IDictionary<,>), "set_Item", out this.CollectionType);
if (null == this.setMethod)
{
this.containsMethod = GetCollectionMethod(this.PropertyType, typeof(ICollection<>), "Contains", out this.CollectionType);
this.addMethod = GetCollectionMethod(this.PropertyType, typeof(ICollection<>), "Add", out this.CollectionType);
this.removeMethod = GetCollectionMethod(this.PropertyType, typeof(ICollection<>), "Remove", out this.CollectionType);
}
}
Debug.Assert(!this.keyProperty || this.IsKnownType, "can't have an random type as key");
}
/// what type was this property declared on?
internal Type DeclaringType
{
get { return this.propertyGetter.DeclaringType; }
}
/// Does this property particpate in the primary key?
internal bool KeyProperty
{
get { return this.keyProperty; }
set { this.keyProperty = value; }
}
/// The other property in this type that holds the MIME type for this one
internal ClientProperty MimeTypeProperty
{
get { return this.mimeTypeProperty; }
set { this.mimeTypeProperty = value; }
}
/// get KeyProperty
/// x
/// KeyProperty
internal static bool GetKeyProperty(ClientProperty x)
{
return x.KeyProperty;
}
/// get property name
/// x
/// PropertyName
internal static string GetPropertyName(ClientProperty x)
{
return x.PropertyName;
}
/// compare name equality
/// x
/// y
/// true if the property names are equal; false otherwise.
internal static bool NameEquality(ClientProperty x, ClientProperty y)
{
return String.Equals(x.PropertyName, y.PropertyName);
}
///
/// get property value from an object
///
/// object to get the property value from
/// property value
internal object GetValue(object instance)
{
Debug.Assert(null != instance, "null instance");
Debug.Assert(null != this.propertyGetter, "null propertyGetter");
return this.propertyGetter.Invoke(instance, null);
}
///
/// remove a item from collection
///
/// collection
/// item to remove
internal void RemoveValue(object instance, object value)
{
Debug.Assert(null != instance, "null instance");
Debug.Assert(null != this.removeMethod, "missing removeMethod");
Debug.Assert(this.PropertyType.IsAssignableFrom(instance.GetType()), "unexpected collection instance");
Debug.Assert((null == value) || this.CollectionType.IsAssignableFrom(value.GetType()), "unexpected collection value to add");
this.removeMethod.Invoke(instance, new object[] { value });
}
///
/// set property value on an object
///
/// object to set the property value on
/// property value
/// used for open type
/// allow add to a collection if available, else allow setting collection property
#if ASTORIA_OPEN_OBJECT
/// cached OpenProperties dictionary
internal void SetValue(object instance, object value, string propertyName, ref object openProperties, bool allowAdd)
#else
internal void SetValue(object instance, object value, string propertyName, bool allowAdd)
#endif
{
Debug.Assert(null != instance, "null instance");
if (null != this.setMethod)
{
#if ASTORIA_OPEN_OBJECT
if (this.OpenObjectProperty)
{
if (null == openProperties)
{
if (null == (openProperties = this.propertyGetter.Invoke(instance, null)))
{
throw Error.NotSupported(Strings.ClientType_NullOpenProperties(this.PropertyName));
}
}
((IDictionary)openProperties)[propertyName] = value;
}
else
#endif
{
Debug.Assert(this.PropertyType.IsAssignableFrom(instance.GetType()), "unexpected dictionary instance");
Debug.Assert((null == value) || this.CollectionType.IsAssignableFrom(value.GetType()), "unexpected dictionary value to set");
// ((IDictionary)instance)[propertyName] = (CollectionType)value;
this.setMethod.Invoke(instance, new object[] { propertyName, value });
}
}
else if (allowAdd && (null != this.addMethod))
{
Debug.Assert(this.PropertyType.IsAssignableFrom(instance.GetType()), "unexpected collection instance");
Debug.Assert((null == value) || this.CollectionType.IsAssignableFrom(value.GetType()), "unexpected collection value to add");
// ((ICollection)instance).Add((CollectionType)value);
if (!(bool)this.containsMethod.Invoke(instance, new object[] { value }))
{
this.addMethod.Invoke(instance, new object[] { value });
}
}
else if (null != this.propertySetter)
{
Debug.Assert((null == value) || this.PropertyType.IsAssignableFrom(value.GetType()), "unexpected property value to set");
// ((ElementType)instance).PropertyName = (PropertyType)value;
this.propertySetter.Invoke(instance, new object[] { value });
}
else
{
throw Error.InvalidOperation(Strings.ClientType_MissingProperty(value.GetType().ToString(), propertyName));
}
}
}
/// equality comparer for TypeName
private sealed class TypeNameEqualityComparer : IEqualityComparer
{
/// equality comparer for TypeName
/// left type
/// right type
/// true if x and y are equal
public bool Equals(TypeName x, TypeName y)
{
return (x.Type == y.Type && x.Name == y.Name);
}
/// compute hashcode for TypeName
/// object to compute hashcode for
/// computed hashcode
public int GetHashCode(TypeName obj)
{
return obj.Type.GetHashCode() ^ obj.Name.GetHashCode();
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// type resolver
//
//---------------------------------------------------------------------
namespace System.Data.Services.Client
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Data.Services.Common;
using System.Linq;
///
/// wrapper around a clr type to
/// get/set properties
/// add items to collections
/// support open types
///
[DebuggerDisplay("{ElementTypeName}")]
internal sealed class ClientType
{
/// what is the clr full name using ToString for generic name expansion
internal readonly string ElementTypeName;
/// what clr type does this represent
internal readonly Type ElementType;
/// if HasKeys then EntityType else if !KnownType then ComplexType else PrimitiveType
internal readonly bool HasKeys;
/// count of keys on entity type
internal readonly int KeyCount;
#region static fields
/// appdomain cache discovered types with properties that we materialize
private static readonly Dictionary types = new Dictionary();
/// cache <T> and wireName to mapped type
private static readonly Dictionary namedTypes = new Dictionary(new TypeNameEqualityComparer());
#endregion
#if ASTORIA_OPEN_OBJECT
/// IDictionary<string,object> OpenProperites { get; }
private readonly ClientProperty openProperties;
#endif
/// properties
private ArraySet properties;
/// Property that holds data for ATOM-style media link entries
private ClientProperty mediaDataMember;
///
/// discover and prepare properties for usage
///
/// type being processed
/// parameter name
/// Whether the skip the check for settable properties.
private ClientType(Type type, string typeName, bool skipSettableCheck)
{
Debug.Assert(null != type, "null type");
Debug.Assert(!String.IsNullOrEmpty(typeName), "empty typeName");
this.ElementTypeName = typeName;
this.ElementType = Nullable.GetUnderlyingType(type) ?? type;
#if ASTORIA_OPEN_OBJECT
string openObjectPropertyName = null;
#endif
if (!ClientConvert.IsKnownType(this.ElementType))
{
#if ASTORIA_OPEN_OBJECT
#region OpenObject determined by walking type hierarchy and looking for [OpenObjectAttribute("PropertyName")]
Type openObjectDeclared = this.ElementType;
for (Type tmp = openObjectDeclared; (null != tmp) && (typeof(object) != tmp); tmp = tmp.BaseType)
{
object[] attributes = openObjectDeclared.GetCustomAttributes(typeof(OpenObjectAttribute), false);
if (1 == attributes.Length)
{
if (null != openObjectPropertyName)
{
throw Error.InvalidOperation(Strings.Clienttype_MultipleOpenProperty(this.ElementTypeName));
}
openObjectPropertyName = ((OpenObjectAttribute)attributes[0]).OpenObjectPropertyName;
openObjectDeclared = tmp;
}
}
#endregion
#endif
Type keyPropertyDeclaredType = null;
DataServiceKeyAttribute dska = type.GetCustomAttributes(true).OfType().FirstOrDefault();
foreach (PropertyInfo pinfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
//// examples where class
//// the normal examples
//// PropertyType Property { get; set }
//// Nullable Property { get; set; }
//// if 'Property: struct' then we would be unable set the property during construction (and have them stick)
//// but when its a class, we can navigate if non-null and set the nested properties
//// PropertyType Property { get; } where PropertyType: class
//// we do support adding elements to collections
//// ICollection { get; /*ignored set;*/ }
//// indexed properties are not suported because
//// we don't have anything to use as the index
//// PropertyType Property[object x] { /*ignored get;*/ /*ignored set;*/ }
//// also ignored
//// if PropertyType.IsPointer (like byte*)
//// if PropertyType.IsArray except for byte[] and char[]
//// if PropertyType == IntPtr or UIntPtr
Type ptype = pinfo.PropertyType; // class / interface / value
ptype = Nullable.GetUnderlyingType(ptype) ?? ptype;
if (ptype.IsPointer ||
(ptype.IsArray && (typeof(byte[]) != ptype) && typeof(char[]) != ptype) ||
(typeof(IntPtr) == ptype) ||
(typeof(UIntPtr) == ptype))
{
continue;
}
Debug.Assert(!ptype.ContainsGenericParameters, "remove when test case is found that encounters this");
if (pinfo.CanRead &&
(!ptype.IsValueType || pinfo.CanWrite) &&
!ptype.ContainsGenericParameters &&
(0 == pinfo.GetIndexParameters().Length))
{
#region IsKey?
bool keyProperty = dska != null ? dska.KeyNames.Contains(pinfo.Name) : false;
if (keyProperty)
{
if (null == keyPropertyDeclaredType)
{
keyPropertyDeclaredType = pinfo.DeclaringType;
}
else if (keyPropertyDeclaredType != pinfo.DeclaringType)
{
throw Error.InvalidOperation(Strings.ClientType_KeysOnDifferentDeclaredType(this.ElementTypeName));
}
if (!ClientConvert.IsKnownType(ptype))
{
throw Error.InvalidOperation(Strings.ClientType_KeysMustBeSimpleTypes(this.ElementTypeName));
}
this.KeyCount++;
}
#endregion
#if ASTORIA_OPEN_OBJECT
#region IsOpenObjectProperty?
bool openProperty = (openObjectPropertyName == pinfo.Name) &&
typeof(IDictionary).IsAssignableFrom(ptype);
Debug.Assert(keyProperty != openProperty || (!keyProperty && !openProperty), "key can't be open type");
#endregion
ClientProperty property = new ClientProperty(pinfo, ptype, keyProperty, openProperty);
if (!property.OpenObjectProperty)
#else
ClientProperty property = new ClientProperty(pinfo, ptype, keyProperty);
#endif
{
if (!this.properties.Add(property, ClientProperty.NameEquality))
{
// 2nd property with same name shadows another property
int shadow = this.IndexOfProperty(property.PropertyName);
if (!property.DeclaringType.IsAssignableFrom(this.properties[shadow].DeclaringType))
{ // the new property is on the most derived class
this.properties.RemoveAt(shadow);
this.properties.Add(property, null);
}
}
}
#if ASTORIA_OPEN_OBJECT
else
{
if (pinfo.DeclaringType == openObjectDeclared)
{
this.openProperties = property;
}
}
#endif
}
}
#region No KeyAttribute, discover key by name pattern { DeclaringType.Name+ID, ID }
if (null == keyPropertyDeclaredType)
{
ClientProperty key = null;
for (int i = this.properties.Count - 1; 0 <= i; --i)
{
string propertyName = this.properties[i].PropertyName;
if (propertyName.EndsWith("ID", StringComparison.Ordinal))
{
string declaringTypeName = this.properties[i].DeclaringType.Name;
if ((propertyName.Length == (declaringTypeName.Length + 2)) &&
propertyName.StartsWith(declaringTypeName, StringComparison.Ordinal))
{
// matched "DeclaringType.Name+ID" pattern
if ((null == keyPropertyDeclaredType) ||
this.properties[i].DeclaringType.IsAssignableFrom(keyPropertyDeclaredType))
{
keyPropertyDeclaredType = this.properties[i].DeclaringType;
key = this.properties[i];
}
}
else if ((null == keyPropertyDeclaredType) && (2 == propertyName.Length))
{
// matched "ID" pattern
keyPropertyDeclaredType = this.properties[i].DeclaringType;
key = this.properties[i];
}
}
}
if (null != key)
{
Debug.Assert(0 == this.KeyCount, "shouldn't have a key yet");
key.KeyProperty = true;
this.KeyCount++;
}
}
else if (this.KeyCount != dska.KeyNames.Count)
{
var m = (from string a in dska.KeyNames
where null == (from b in this.properties
where b.PropertyName == a
select b).FirstOrDefault()
select a).First();
throw Error.InvalidOperation(Strings.ClientType_MissingProperty(this.ElementTypeName, m));
}
#endregion
this.HasKeys = (null != keyPropertyDeclaredType);
Debug.Assert(this.KeyCount == this.Properties.Where(k => k.KeyProperty).Count(), "KeyCount mismatch");
this.WireUpMimeTypeProperties();
this.CheckMediaLinkEntry();
if (!skipSettableCheck)
{
#if ASTORIA_OPEN_OBJECT
if ((0 == this.properties.Count) && (null == this.openProperties))
#else
if (0 == this.properties.Count)
#endif
{ // implicit construction?
throw Error.InvalidOperation(Strings.ClientType_NoSettableFields(this.ElementTypeName));
}
}
}
this.properties.Sort(ClientProperty.GetPropertyName, String.CompareOrdinal);
#if ASTORIA_OPEN_OBJECT
#region Validate OpenObjectAttribute was used
if ((null != openObjectPropertyName) && (null == this.openProperties))
{
throw Error.InvalidOperation(Strings.ClientType_MissingOpenProperty(this.ElementTypeName, openObjectPropertyName));
}
Debug.Assert((null != openObjectPropertyName) == (null != this.openProperties), "OpenProperties mismatch");
#endregion
#endif
}
/// Properties sorted by name
internal ArraySet Properties
{
get { return this.properties; }
}
/// Property that holds data for ATOM-style media link entries
internal ClientProperty MediaDataMember
{
get { return this.mediaDataMember; }
}
///
/// get a client type resolver
///
/// type to wrap
/// client type
internal static ClientType Create(Type type)
{
return Create(type, true /* expectModelType */);
}
///
/// get a client type resolver
///
/// type to wrap
/// Whether the type is expected to be a model type.
/// client type
internal static ClientType Create(Type type, bool expectModelType)
{
ClientType clientType;
lock (ClientType.types)
{
ClientType.types.TryGetValue(type, out clientType);
}
if (null == clientType)
{
bool skipSettableCheck = !expectModelType;
clientType = new ClientType(type, type.ToString(), skipSettableCheck); // ToString expands generic type name where as FullName does not
if (expectModelType)
{
lock (ClientType.types)
{
ClientType existing;
if (ClientType.types.TryGetValue(type, out existing))
{
clientType = existing;
}
else
{
ClientType.types.Add(type, clientType);
}
}
}
}
return clientType;
}
#if !ASTORIA_LIGHT
///
/// resolve the wireName/userType pair to a CLR type
///
/// type name sent by server
/// type passed by user or on propertyType from a class
/// mapped clr type
internal static Type ResolveFromName(string wireName, Type userType)
#else
///
/// resolve the wireName/userType pair to a CLR type
///
/// type name sent by server
/// type passed by user or on propertyType from a class
/// typeof context for strongly typed assembly
/// mapped clr type
internal static Type ResolveFromName(string wireName, Type userType, Type contextType)
#endif
{
Type foundType;
TypeName typename;
typename.Type = userType;
typename.Name = wireName;
lock (ClientType.namedTypes)
{
ClientType.namedTypes.TryGetValue(typename, out foundType);
}
if (null == foundType)
{
string name = wireName;
int index = wireName.LastIndexOf('.');
if ((0 <= index) && (index < wireName.Length - 1))
{
name = wireName.Substring(index + 1);
}
if (userType.Name == name)
{
foundType = userType;
}
else
{
#if !ASTORIA_LIGHT
// searching only loaded assemblies, not referenced assemblies
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
#else
foreach (Assembly assembly in new Assembly[] { userType.Assembly, contextType.Assembly }.Distinct())
#endif
{
Type found = assembly.GetType(wireName, false);
ResolveSubclass(name, userType, found, ref foundType);
if (null == found)
{
Type[] types = null;
try
{
types = assembly.GetTypes();
}
catch (ReflectionTypeLoadException)
{
}
if (null != types)
{
foreach (Type t in types)
{
ResolveSubclass(name, userType, t, ref foundType);
}
}
}
}
}
if (null != foundType)
{
lock (ClientType.namedTypes)
{
ClientType.namedTypes[typename] = foundType;
}
}
}
return foundType;
}
///
/// get concrete type that implements the genericTypeDefinitation
///
/// starting type
/// the generic type definition to find
/// concrete type that implementats the generic type
internal static Type GetImplementationType(Type propertyType, Type genericTypeDefinition)
{
if (IsConstructedGeneric(propertyType, genericTypeDefinition))
{ // propertyType is ICollection
return propertyType;
}
else
{
Type implementationType = null;
foreach (Type interfaceType in propertyType.GetInterfaces())
{
if (IsConstructedGeneric(interfaceType, genericTypeDefinition))
{
if (null == implementationType)
{ // found implmentation of ICollection
implementationType = interfaceType;
}
else
{ // ICollection and ICollection
throw Error.NotSupported(Strings.ClientType_MultipleImplementationNotSupported);
}
}
}
return implementationType;
}
}
///
/// get element type, resolves ICollection and Nullable
///
/// starting type
/// the generic type definition to find
/// the method to search for
/// the collection type if found
/// element types
internal static MethodInfo GetCollectionMethod(Type propertyType, Type genericTypeDefinition, string methodName, out Type type)
{
Debug.Assert(null != propertyType, "null propertyType");
Debug.Assert(null != genericTypeDefinition, "null genericTypeDefinition");
Debug.Assert(genericTypeDefinition.IsGenericTypeDefinition, "!IsGenericTypeDefinition");
type = null;
Type implementationType = GetImplementationType(propertyType, genericTypeDefinition);
if (null != implementationType)
{
Type[] genericArguments = implementationType.GetGenericArguments();
MethodInfo methodInfo = implementationType.GetMethod(methodName);
Debug.Assert(null != methodInfo, "should have found the method");
#if DEBUG
Debug.Assert(null != genericArguments, "null genericArguments");
ParameterInfo[] parameters = methodInfo.GetParameters();
if (0 < parameters.Length)
{
// following assert was disabled for Contains which returns bool
// Debug.Assert(typeof(void) == methodInfo.ReturnParameter.ParameterType, "method doesn't return void");
Debug.Assert(genericArguments.Length == parameters.Length, "genericArguments don't match parameters");
for (int i = 0; i < genericArguments.Length; ++i)
{
Debug.Assert(genericArguments[i] == parameters[i].ParameterType, "parameter doesn't match generic argument");
}
}
#endif
type = genericArguments[genericArguments.Length - 1];
return methodInfo;
}
return null;
}
///
/// create object using default constructor
///
/// instance of propertyType
internal object CreateInstance()
{
return Activator.CreateInstance(this.ElementType);
}
///
/// get property wrapper for a property name, might be method around open types for otherwise unknown properties
///
/// property name
/// are missing properties ignored
/// property wrapper
/// for unknown properties on closed types
internal ClientProperty GetProperty(string propertyName, bool ignoreMissingProperties)
{
int index = this.IndexOfProperty(propertyName);
if (0 <= index)
{
return this.properties[index];
}
#if ASTORIA_OPEN_OBJECT
else if (null != this.openProperties)
{
return this.openProperties;
}
#endif
else if (!ignoreMissingProperties)
{
throw Error.InvalidOperation(Strings.ClientType_MissingProperty(this.ElementTypeName, propertyName));
}
return null;
}
///
/// Checks whether the specified is a
/// closed constructed type of the generic type.
///
/// Type to check.
/// Generic type for checkin.
/// true if is a constructed type of .
/// The check is an immediate check; no inheritance rules are applied.
private static bool IsConstructedGeneric(Type type, Type genericTypeDefinition)
{
Debug.Assert(type != null, "type != null");
Debug.Assert(!type.ContainsGenericParameters, "remove when test case is found that encounters this");
Debug.Assert(genericTypeDefinition != null, "genericTypeDefinition != null");
return type.IsGenericType && (type.GetGenericTypeDefinition() == genericTypeDefinition) && !type.ContainsGenericParameters;
}
///
/// is the type a visible subclass with correct name
///
/// type name from server
/// the type from user for materialization or property type
/// type being tested
/// the previously discovered matching type
/// if the mapping is ambiguous
private static void ResolveSubclass(string wireClassName, Type userType, Type type, ref Type existing)
{
if ((null != type) && type.IsVisible && (wireClassName == type.Name) && userType.IsAssignableFrom(type))
{
if (null != existing)
{
throw Error.InvalidOperation(Strings.Deserialize_Current(existing, type));
}
existing = type;
}
}
/// get the index of a property
/// propertyName
/// index else -1
private int IndexOfProperty(string propertyName)
{
return this.properties.IndexOf(propertyName, ClientProperty.GetPropertyName, String.Equals);
}
///
/// Find properties with dynamic MIME type related properties and
/// set the references from each ClientProperty to its related MIME type property
///
private void WireUpMimeTypeProperties()
{
MimeTypePropertyAttribute attribute = (MimeTypePropertyAttribute)this.ElementType.GetCustomAttributes(typeof(MimeTypePropertyAttribute), true).SingleOrDefault();
if (null != attribute)
{
int dataIndex, mimeTypeIndex;
if ((0 > (dataIndex = this.IndexOfProperty(attribute.DataPropertyName))) ||
(0 > (mimeTypeIndex = this.IndexOfProperty(attribute.MimeTypePropertyName))))
{
throw Error.InvalidOperation(Strings.ClientType_MissingMimeTypeProperty(attribute.DataPropertyName, attribute.MimeTypePropertyName));
}
Debug.Assert(0 <= dataIndex, "missing data property");
Debug.Assert(0 <= mimeTypeIndex, "missing mime type property");
this.Properties[dataIndex].MimeTypeProperty = this.Properties[mimeTypeIndex];
}
}
///
/// Check if this type represents an ATOM-style media link entry and
/// if so mark the ClientType as such
///
private void CheckMediaLinkEntry()
{
object[] attributes = this.ElementType.GetCustomAttributes(typeof(MediaEntryAttribute), true);
if (attributes != null && attributes.Length > 0)
{
Debug.Assert(attributes.Length == 1, "The AttributeUsage in the attribute definition should be presenting more than 1 per property");
int index = this.IndexOfProperty(((MediaEntryAttribute)attributes[0]).MediaMemberName);
if (index < 0)
{
throw Error.InvalidOperation(Strings.ClientType_MissingMediaEntryProperty(
((MediaEntryAttribute)attributes[0]).MediaMemberName));
}
this.mediaDataMember = this.properties[index];
}
}
/// type + wireName combination
private struct TypeName
{
/// type
internal Type Type;
/// type name from server
internal string Name;
}
///
/// wrapper around property methods
///
[DebuggerDisplay("{PropertyName}")]
internal sealed class ClientProperty
{
/// property name for debugging
internal readonly string PropertyName;
/// type of the property
internal readonly Type NullablePropertyType;
/// type of the property
internal readonly Type PropertyType;
/// what is the nested collection element
internal readonly Type CollectionType;
///
/// Is this a known primitive/reference type or an entity/complex/collection type?
///
internal readonly bool IsKnownType;
#if ASTORIA_OPEN_OBJECT
/// IDictionary<string,object> OpenProperites { get; }
internal readonly bool OpenObjectProperty;
#endif
/// property getter
private readonly MethodInfo propertyGetter;
/// property setter
private readonly MethodInfo propertySetter;
/// "set_Item" method supporting IDictionary properties
private readonly MethodInfo setMethod;
/// "Add" method supporting ICollection<> properties
private readonly MethodInfo addMethod;
/// "Remove" method supporting ICollection<> properties
private readonly MethodInfo removeMethod;
/// "Contains" method support ICollection<> properties
private readonly MethodInfo containsMethod;
/// IsKeyProperty?
private bool keyProperty;
/// The other property in this type that holds the MIME type for this one
private ClientProperty mimeTypeProperty;
///
/// constructor
///
/// property
/// propertyType
/// keyProperty
#if ASTORIA_OPEN_OBJECT
/// openObjectProperty
internal ClientProperty(PropertyInfo property, Type propertyType, bool keyProperty, bool openObjectProperty)
#else
internal ClientProperty(PropertyInfo property, Type propertyType, bool keyProperty)
#endif
{
Debug.Assert(null != property, "null property");
Debug.Assert(null != propertyType, "null propertyType");
Debug.Assert(null == Nullable.GetUnderlyingType(propertyType), "should already have been denullified");
this.PropertyName = property.Name;
this.NullablePropertyType = property.PropertyType;
this.PropertyType = propertyType;
this.propertyGetter = property.GetGetMethod();
this.propertySetter = property.GetSetMethod();
this.keyProperty = keyProperty;
#if ASTORIA_OPEN_OBJECT
this.OpenObjectProperty = openObjectProperty;
#endif
this.IsKnownType = ClientConvert.IsKnownType(propertyType);
if (!this.IsKnownType)
{
this.setMethod = GetCollectionMethod(this.PropertyType, typeof(IDictionary<,>), "set_Item", out this.CollectionType);
if (null == this.setMethod)
{
this.containsMethod = GetCollectionMethod(this.PropertyType, typeof(ICollection<>), "Contains", out this.CollectionType);
this.addMethod = GetCollectionMethod(this.PropertyType, typeof(ICollection<>), "Add", out this.CollectionType);
this.removeMethod = GetCollectionMethod(this.PropertyType, typeof(ICollection<>), "Remove", out this.CollectionType);
}
}
Debug.Assert(!this.keyProperty || this.IsKnownType, "can't have an random type as key");
}
/// what type was this property declared on?
internal Type DeclaringType
{
get { return this.propertyGetter.DeclaringType; }
}
/// Does this property particpate in the primary key?
internal bool KeyProperty
{
get { return this.keyProperty; }
set { this.keyProperty = value; }
}
/// The other property in this type that holds the MIME type for this one
internal ClientProperty MimeTypeProperty
{
get { return this.mimeTypeProperty; }
set { this.mimeTypeProperty = value; }
}
/// get KeyProperty
/// x
/// KeyProperty
internal static bool GetKeyProperty(ClientProperty x)
{
return x.KeyProperty;
}
/// get property name
/// x
/// PropertyName
internal static string GetPropertyName(ClientProperty x)
{
return x.PropertyName;
}
/// compare name equality
/// x
/// y
/// true if the property names are equal; false otherwise.
internal static bool NameEquality(ClientProperty x, ClientProperty y)
{
return String.Equals(x.PropertyName, y.PropertyName);
}
///
/// get property value from an object
///
/// object to get the property value from
/// property value
internal object GetValue(object instance)
{
Debug.Assert(null != instance, "null instance");
Debug.Assert(null != this.propertyGetter, "null propertyGetter");
return this.propertyGetter.Invoke(instance, null);
}
///
/// remove a item from collection
///
/// collection
/// item to remove
internal void RemoveValue(object instance, object value)
{
Debug.Assert(null != instance, "null instance");
Debug.Assert(null != this.removeMethod, "missing removeMethod");
Debug.Assert(this.PropertyType.IsAssignableFrom(instance.GetType()), "unexpected collection instance");
Debug.Assert((null == value) || this.CollectionType.IsAssignableFrom(value.GetType()), "unexpected collection value to add");
this.removeMethod.Invoke(instance, new object[] { value });
}
///
/// set property value on an object
///
/// object to set the property value on
/// property value
/// used for open type
/// allow add to a collection if available, else allow setting collection property
#if ASTORIA_OPEN_OBJECT
/// cached OpenProperties dictionary
internal void SetValue(object instance, object value, string propertyName, ref object openProperties, bool allowAdd)
#else
internal void SetValue(object instance, object value, string propertyName, bool allowAdd)
#endif
{
Debug.Assert(null != instance, "null instance");
if (null != this.setMethod)
{
#if ASTORIA_OPEN_OBJECT
if (this.OpenObjectProperty)
{
if (null == openProperties)
{
if (null == (openProperties = this.propertyGetter.Invoke(instance, null)))
{
throw Error.NotSupported(Strings.ClientType_NullOpenProperties(this.PropertyName));
}
}
((IDictionary)openProperties)[propertyName] = value;
}
else
#endif
{
Debug.Assert(this.PropertyType.IsAssignableFrom(instance.GetType()), "unexpected dictionary instance");
Debug.Assert((null == value) || this.CollectionType.IsAssignableFrom(value.GetType()), "unexpected dictionary value to set");
// ((IDictionary)instance)[propertyName] = (CollectionType)value;
this.setMethod.Invoke(instance, new object[] { propertyName, value });
}
}
else if (allowAdd && (null != this.addMethod))
{
Debug.Assert(this.PropertyType.IsAssignableFrom(instance.GetType()), "unexpected collection instance");
Debug.Assert((null == value) || this.CollectionType.IsAssignableFrom(value.GetType()), "unexpected collection value to add");
// ((ICollection)instance).Add((CollectionType)value);
if (!(bool)this.containsMethod.Invoke(instance, new object[] { value }))
{
this.addMethod.Invoke(instance, new object[] { value });
}
}
else if (null != this.propertySetter)
{
Debug.Assert((null == value) || this.PropertyType.IsAssignableFrom(value.GetType()), "unexpected property value to set");
// ((ElementType)instance).PropertyName = (PropertyType)value;
this.propertySetter.Invoke(instance, new object[] { value });
}
else
{
throw Error.InvalidOperation(Strings.ClientType_MissingProperty(value.GetType().ToString(), propertyName));
}
}
}
/// equality comparer for TypeName
private sealed class TypeNameEqualityComparer : IEqualityComparer
{
/// equality comparer for TypeName
/// left type
/// right type
/// true if x and y are equal
public bool Equals(TypeName x, TypeName y)
{
return (x.Type == y.Type && x.Name == y.Name);
}
/// compute hashcode for TypeName
/// object to compute hashcode for
/// computed hashcode
public int GetHashCode(TypeName obj)
{
return obj.Type.GetHashCode() ^ obj.Name.GetHashCode();
}
}
}
}
// 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
- filewebrequest.cs
- CodeTypeParameterCollection.cs
- WindowsClientCredential.cs
- BitmapCacheBrush.cs
- PtsPage.cs
- TreeNodeBindingCollection.cs
- ServiceMetadataExtension.cs
- KeyValuePair.cs
- CultureSpecificStringDictionary.cs
- KeyPressEvent.cs
- DESCryptoServiceProvider.cs
- CheckBoxPopupAdapter.cs
- DataGridViewImageCell.cs
- Int32EqualityComparer.cs
- Point.cs
- BindingBase.cs
- RoleGroupCollection.cs
- ConnectionPointCookie.cs
- LayoutEngine.cs
- IndexerNameAttribute.cs
- BindingContext.cs
- ValidationHelper.cs
- RuleDefinitions.cs
- WebBrowserBase.cs
- IndividualDeviceConfig.cs
- SqlDataSourceCache.cs
- SudsCommon.cs
- NamespaceEmitter.cs
- DesignSurfaceCollection.cs
- DiscoveryMessageSequenceGenerator.cs
- CodeSubDirectory.cs
- DashStyles.cs
- LayoutTable.cs
- BufferModesCollection.cs
- ItemCheckEvent.cs
- MessageBox.cs
- ArraySegment.cs
- PrtTicket_Public.cs
- TextTabProperties.cs
- FigureParaClient.cs
- HttpCacheVary.cs
- EncryptedPackage.cs
- ServiceOperationWrapper.cs
- TakeQueryOptionExpression.cs
- WindowsImpersonationContext.cs
- SqlUtil.cs
- StrokeCollectionDefaultValueFactory.cs
- MenuItemBindingCollection.cs
- SelectedDatesCollection.cs
- TypeTypeConverter.cs
- SmtpFailedRecipientException.cs
- filewebresponse.cs
- MimeTextImporter.cs
- ProtocolsConfiguration.cs
- XPathScanner.cs
- DesignerAttributeInfo.cs
- ControlPaint.cs
- RegexRunnerFactory.cs
- UniqueIdentifierService.cs
- NodeLabelEditEvent.cs
- ManagedWndProcTracker.cs
- WindowsListViewItemCheckBox.cs
- FileDialogPermission.cs
- ScriptManager.cs
- DoubleLinkListEnumerator.cs
- RoleGroup.cs
- ElementHostAutomationPeer.cs
- Vector.cs
- BamlTreeUpdater.cs
- DataServiceClientException.cs
- NavigatingCancelEventArgs.cs
- WebPartUtil.cs
- PropertyEmitter.cs
- XmlUrlResolver.cs
- Token.cs
- PersonalizationStateInfoCollection.cs
- CodeGenerator.cs
- BitmapSizeOptions.cs
- ParentUndoUnit.cs
- TypedElement.cs
- FacetValues.cs
- GenericIdentity.cs
- UrlAuthorizationModule.cs
- TabPage.cs
- PageCatalogPart.cs
- DriveNotFoundException.cs
- TextReader.cs
- FileSystemEnumerable.cs
- ClaimSet.cs
- SymLanguageType.cs
- SQLResource.cs
- CreateUserWizard.cs
- WebConfigurationManager.cs
- Item.cs
- Function.cs
- SafeNativeMethods.cs
- DataServiceSaveChangesEventArgs.cs
- ConfigPathUtility.cs
- ByteAnimationUsingKeyFrames.cs
- StrongNameKeyPair.cs