/// <summary> /// Builds a mapping of member name to field/property /// </summary> /// <param name="objectType"></param> private IEnumerable <DataName> BuildMap(Type objectType, out IDictionary <string, MemberMap> maps) { bool hasName = false; IEnumerable <DataName> typeNames = this.Strategy.GetName(objectType); if (typeNames != null) { foreach (DataName typeName in typeNames) { if (!typeName.IsEmpty) { hasName = true; break; } } } if (!hasName) { typeNames = new [] { new DataName(objectType) }; } if (objectType.IsEnum) { // create special maps for enum types IDictionary <Enum, string> enumMap; maps = this.BuildEnumMap(objectType, out enumMap); return(typeNames); } // do not incurr the cost of member map for dictionaries if (typeof(IDictionary <string, object>).IsAssignableFrom(objectType) || typeof(IDictionary).IsAssignableFrom(objectType)) { #if SILVERLIGHT && (NET20 || NET30 || NET35) lock (this.MemberCache) lock (this.NameCache) #elif NET20 || NET30 this.MapLock.AcquireWriterLock(ResolverCache.LockTimeout); #elif NET35 this.MapLock.EnterWriteLock(); #endif #if !NET40 try #endif { // store marker in cache for future lookups maps = (this.MemberCache[objectType] = null); return(this.NameCache[objectType] = typeNames); } #if !NET40 finally #endif { #if SILVERLIGHT && (NET20 || NET30 || NET35) // noop #elif NET20 || NET30 this.MapLock.ReleaseWriterLock(); #elif NET35 this.MapLock.ExitWriteLock(); #endif } } // create new mapping maps = new Dictionary <string, MemberMap>(); bool isImmutableType = FactoryMap.IsImmutableType(objectType); // load properties into property map foreach (PropertyInfo info in objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)) { // Ignore indexer properties as aren't serialized // https://bugzilla.xamarin.com/show_bug.cgi?id=6821#c5 if (info.GetIndexParameters().Length != 0 || this.Strategy.IsPropertyIgnored(info, isImmutableType)) { continue; } IEnumerable <DataName> names = this.Strategy.GetName(info); hasName = false; if (names != null) { foreach (DataName name in names) { if (!name.IsEmpty) { hasName = true; break; } } } if (!hasName) { names = new[] { new DataName(info.Name) }; } ValueIgnoredDelegate isIgnored = this.Strategy.GetValueIgnoredCallback(info); MemberMap map = null; foreach (DataName name in names) { if (name.IsEmpty || maps.ContainsKey(name.LocalName)) { continue; } if (map == null) { maps[name.LocalName] = map = new MemberMap(info, name, isIgnored); } else { maps[name.LocalName] = new MemberMap(map, name); } } } // load fields into property map foreach (FieldInfo info in objectType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)) { if (this.Strategy.IsFieldIgnored(info)) { continue; } IEnumerable <DataName> names = this.Strategy.GetName(info); hasName = false; if (names != null) { foreach (DataName name in names) { if (!name.IsEmpty) { hasName = true; break; } } } if (!hasName) { names = new[] { new DataName(info.Name) }; } ValueIgnoredDelegate isIgnored = this.Strategy.GetValueIgnoredCallback(info); MemberMap map = null; foreach (DataName name in names) { if (name.IsEmpty || maps.ContainsKey(name.LocalName)) { continue; } if (map == null) { maps[name.LocalName] = map = new MemberMap(info, name, isIgnored); } else { maps[name.LocalName] = new MemberMap(map, name); } } } #if SILVERLIGHT && (NET20 || NET30 || NET35) lock (this.MemberCache) lock (this.NameCache) #elif NET20 || NET30 this.MapLock.AcquireWriterLock(ResolverCache.LockTimeout); #elif NET35 this.MapLock.EnterWriteLock(); #endif #if !NET40 try #endif { // store in cache for future requests this.MemberCache[objectType] = maps; return(this.NameCache[objectType] = typeNames); } #if !NET40 finally #endif { #if SILVERLIGHT && (NET20 || NET30 || NET35) // noop #elif NET20 || NET30 this.MapLock.ReleaseWriterLock(); #elif NET35 this.MapLock.ExitWriteLock(); #endif } }
public FactoryMap LoadFactory(Type type) { if (type == null || type == typeof(object)) { return(null); } FactoryMap map; #if SILVERLIGHT && (NET20 || NET30 || NET35) lock (this.Factories) #elif NET20 || NET30 this.FactoryLock.AcquireReaderLock(ResolverCache.LockTimeout); #elif NET35 this.FactoryLock.EnterReadLock(); #endif #if !NET40 try #endif { if (this.Factories.TryGetValue(type, out map)) { return(map); } } #if !NET40 finally #endif { #if SILVERLIGHT && (NET20 || NET30 || NET35) // noop #elif NET20 || NET30 this.FactoryLock.ReleaseReaderLock(); #elif NET35 this.FactoryLock.ExitReadLock(); #endif } map = new FactoryMap(type); #if SILVERLIGHT && (NET20 || NET30 || NET35) lock (this.Factories) #elif NET20 || NET30 this.FactoryLock.AcquireWriterLock(ResolverCache.LockTimeout); #elif NET35 this.FactoryLock.EnterWriteLock(); #endif #if !NET40 try #endif { // store in cache for future requests return(this.Factories[type] = map); } #if !NET40 finally #endif { #if SILVERLIGHT && (NET20 || NET30 || NET35) // noop #elif NET20 || NET30 this.FactoryLock.ReleaseWriterLock(); #elif NET35 this.FactoryLock.ExitWriteLock(); #endif } }
/// <summary> /// Ctor /// </summary> public FactoryMap(Type type) { if (type == null) { throw new ArgumentNullException("type"); } if (FactoryMap.IsInvalidType(type)) { throw new TypeLoadException(String.Format( FactoryMap.ErrorCannotInstantiate, type.FullName)); } this.Ctor = DynamicMethodGenerator.GetTypeFactory(type); ConstructorInfo[] ctors; if (!typeof(IEnumerable).IsAssignableFrom(type)) { if (this.Ctor != null) { return; } ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy); if (ctors.Length == 1) { ConstructorInfo ctor = ctors[0]; this.Ctor = DynamicMethodGenerator.GetTypeFactory(ctor); this.CtorArgs = ctor.GetParameters(); } return; } // many ICollection types take an IEnumerable or ICollection // as a constructor argument. look through constructors for // a compatible match. ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy); this.CollectionCtors = new Dictionary <Type, FactoryDelegate>(ctors.Length); foreach (ConstructorInfo ctor in ctors) { ParameterInfo[] paramList = ctor.GetParameters(); if (paramList.Length != 1) { continue; } Type argType = paramList[0].ParameterType; if ((argType == typeof(string)) || ( #if !NETCF (argType.GetInterface(TypeCoercionUtility.TypeGenericIEnumerable, false) == null) && #endif (typeof(IEnumerable).IsAssignableFrom(argType)))) { continue; } // save all constructors that can take an enumerable of objects this.CollectionCtors[argType] = DynamicMethodGenerator.GetTypeFactory(ctor); } if (this.Ctor == null) { // try to grab a private ctor if exists this.Ctor = DynamicMethodGenerator.GetTypeFactory(type); } // many collection types have an AddRange method // which adds a collection of items at once MethodInfo methodInfo = type.GetMethod("AddRange"); if (methodInfo != null) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 1) { this.AddRange = DynamicMethodGenerator.GetMethodProxy(methodInfo); this.AddRangeType = parameters[0].ParameterType; } } // many collection types have an Add method // which adds items one at a time Type collectionType = null; #if !NETCF collectionType = type.GetInterface(TypeCoercionUtility.TypeGenericICollection, false); #endif if (collectionType != null) { methodInfo = collectionType.GetMethod("Add"); } else { methodInfo = type.GetMethod("Add"); } if (methodInfo != null) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 1) { this.Add = DynamicMethodGenerator.GetMethodProxy(methodInfo); this.AddType = parameters[0].ParameterType; } } }