internal static BinaryPropertyInfo CreateProperty( TypeMap typeMap, Type declaredPropertyType, Type runtimePropertyType, MemberInfo memberInfo, Type parentClassType, BinaryConverter converter, BinarySerializerOptions options, BinaryIgnoreCondition?ignoreCondition = null) { // Create the BinaryPropertyInfo instance. BinaryPropertyInfo binaryPropertyInfo = converter.CreateBinaryPropertyInfo(); binaryPropertyInfo.Initialize( typeMap, parentClassType, declaredPropertyType, runtimePropertyType, runtimeClassType: converter.ClassType, memberInfo, converter, ignoreCondition, options); return(binaryPropertyInfo); }
public void EndProperty() { DeclaredBinaryPropertyInfo = null !; BinaryPropertyNameAsString = null; PolymorphicBinaryPropertyInfo = null; PropertyState = StackFramePropertyState.None; }
public static BinaryPropertyInfo AddProperty( TypeMap typeMap, MemberInfo memberInfo, Type memberType, Type parentClassType, BinarySerializerOptions options) { BinaryIgnoreCondition?ignoreCondition = BinaryPropertyInfo.GetAttribute <BinaryIgnoreAttribute>(memberInfo)?.Condition; if (ignoreCondition == BinaryIgnoreCondition.Always) { return(BinaryPropertyInfo.CreateIgnoredPropertyPlaceholder(typeMap, memberInfo, options)); } BinaryConverter converter = GetConverter( memberType, parentClassType, memberInfo, out Type runtimeType, options); return(CreateProperty( typeMap, declaredPropertyType: memberType, runtimePropertyType: runtimeType, memberInfo, parentClassType, converter, options, ignoreCondition)); }
internal static void CreateDataExtensionProperty( ref ReadStack state, object obj, BinaryPropertyInfo binaryPropertyInfo) { Debug.Assert(binaryPropertyInfo != null); object extensionData = binaryPropertyInfo.GetValueAsObject(obj); if (extensionData == null) { // Create the appropriate dictionary type. We already verified the types. #if DEBUG Type underlyingIDictionaryType = binaryPropertyInfo.DeclaredPropertyType.GetCompatibleGenericInterface(typeof(IDictionary <,>)) !; Type[] genericArgs = underlyingIDictionaryType.GetGenericArguments(); Debug.Assert(underlyingIDictionaryType.IsGenericType); Debug.Assert(genericArgs.Length == 2); Debug.Assert(genericArgs[0].UnderlyingSystemType == typeof(string)); Debug.Assert( genericArgs[1].UnderlyingSystemType == BinaryClassInfo.ObjectType); #endif if (binaryPropertyInfo.RuntimeClassInfo.CreateObject == null) { ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(binaryPropertyInfo.DeclaredPropertyType); } extensionData = binaryPropertyInfo.RuntimeClassInfo.CreateObject(); binaryPropertyInfo.SetExtensionDictionaryAsObject(ref state, obj, extensionData); } // We don't add the value to the dictionary here because we need to support the read-ahead functionality for Streams. }
// Create a parameter that is ignored at run-time. It uses the same type (typeof(sbyte)) to help // prevent issues with unsupported types and helps ensure we don't accidently (de)serialize it. public static BinaryParameterInfo CreateIgnoredParameterPlaceholder(BinaryPropertyInfo matchingProperty) { return(new BinaryParameterInfo <sbyte> { RuntimePropertyType = typeof(sbyte), NameAsUtf8Bytes = matchingProperty.NameAsUtf8Bytes !, TypeMap = matchingProperty.TypeMap });
public BinaryClassInfo([NotNull] Type type, [NotNull] TypeMap typeMap, [NotNull] BinarySerializerOptions options) { TypeMap = typeMap; Type = type; Options = options; BinaryConverter converter = GetConverter( Type, parentClassType: null, // A ClassInfo never has a "parent" class. memberInfo: null, // A ClassInfo never has a "parent" property. out Type runtimeType, Options); ClassType = converter.ClassType; PropertyInfoForClassInfo = CreatePropertyInfoForClassInfo(TypeMap, Type, runtimeType, converter, Options); TypeSeq = converter.GetTypeSeq(typeMap, options); switch (ClassType) { case ClassType.Object: { CreateObject = Options.MemberAccessorStrategy.CreateConstructor(type); GetObjectMemberInfos(type, typeMap, converter); } break; case ClassType.Enumerable: case ClassType.Dictionary: { ElementType = converter.ElementType; CreateObject = Options.MemberAccessorStrategy.CreateConstructor(runtimeType); GetObjectMemberInfos(type, typeMap, converter, true); } break; case ClassType.Value: case ClassType.NewValue: { CreateObject = Options.MemberAccessorStrategy.CreateConstructor(type); } break; case ClassType.None: { ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(type); } break; default: Debug.Fail($"Unexpected class type: {ClassType}"); throw new InvalidOperationException(); } }
public void EndProperty() { BinaryPropertyInfo = null !; BinaryPropertyName = null; BinaryPropertyNameAsString = null; PropertyState = StackFramePropertyState.None; ValidateEndTokenOnArray = false; PropertyPolymorphicConverter = null; // No need to clear these since they are overwritten each time: // NumberHandling // UseExtensionProperty }
/// <summary> /// Initializes the state for polymorphic or re-entry cases. /// </summary> public BinaryConverter InitializeReEntry(Type type, BinarySerializerOptions options, string propertyName = null) { BinaryClassInfo classInfo = options.GetOrAddClass(type); // Set for exception handling calculation of BinaryPath. BinaryPropertyNameAsString = propertyName; PolymorphicBinaryPropertyInfo = classInfo.PropertyInfoForClassInfo; //PolymorphicBinaryClassInfo = classInfo; //PolymorphicBinaryTypeInfo = classInfo.TypeMap.GetTypeInfo(classInfo.TypeSeq); return(PolymorphicBinaryPropertyInfo.ConverterBase); }
public static BinaryPropertyInfo GetPropertyPlaceholder() { BinaryPropertyInfo info = new BinaryPropertyInfo <object>(); Debug.Assert(!info.IsForClassInfo); Debug.Assert(!info.ShouldDeserialize); Debug.Assert(!info.ShouldSerialize); info.NameAsString = string.Empty; return(info); }
private void CacheMember( Type declaringType, Type memberType, MemberInfo memberInfo, Dictionary <string, BinaryPropertyInfo> cache, ref Dictionary <string, MemberInfo> ignoredMembers) { BinaryPropertyInfo binaryPropertyInfo = AddProperty(TypeMap, memberInfo, memberType, declaringType, Options); Debug.Assert(binaryPropertyInfo.NameAsString != null); string memberName = memberInfo.Name; // The BinaryPropertyNameAttribute or naming policy resulted in a collision. if (!cache.TryAdd(binaryPropertyInfo.NameAsString, binaryPropertyInfo)) { BinaryPropertyInfo other = cache[binaryPropertyInfo.NameAsString]; if (other.IsIgnored) { // Overwrite previously cached property since it has [BinaryIgnore]. cache[binaryPropertyInfo.NameAsString] = binaryPropertyInfo; } else if ( // Does the current property have `BinaryIgnoreAttribute`? !binaryPropertyInfo.IsIgnored && // Is the current property hidden by the previously cached property // (with `new` keyword, or by overriding)? other.MemberInfo !.Name != memberName && // Was a property with the same CLR name was ignored? That property hid the current property, // thus, if it was ignored, the current property should be ignored too. ignoredMembers?.ContainsKey(memberName) != true) { // We throw if we have two public properties that have the same property name, and neither have been ignored. ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, binaryPropertyInfo); } // Ignore the current property. } else { int seq = System.Threading.Interlocked.Increment(ref _propertySeq); binaryPropertyInfo.Seq = (ushort)seq; } if (binaryPropertyInfo.IsIgnored) { (ignoredMembers ??= new Dictionary <string, MemberInfo>()).Add(memberName, memberInfo); } }
public virtual void Initialize( TypeMap typeMap, Type runtimePropertyType, ParameterInfo parameterInfo, BinaryPropertyInfo matchingProperty, BinarySerializerOptions options) { TypeMap = typeMap; RuntimePropertyType = runtimePropertyType; Position = parameterInfo?.Position ?? 0; NameAsUtf8Bytes = matchingProperty.NameAsUtf8Bytes !; Options = options; ShouldDeserialize = true; ConverterBase = matchingProperty.ConverterBase; IgnoreDefaultValuesOnRead = matchingProperty.IgnoreDefaultValuesOnRead; }
// Create a property that is ignored at run-time. It uses the same type (typeof(sbyte)) to help // prevent issues with unsupported types and helps ensure we don't accidently (de)serialize it. public static BinaryPropertyInfo CreateIgnoredPropertyPlaceholder(TypeMap typeMap, MemberInfo memberInfo, BinarySerializerOptions options) { BinaryPropertyInfo binaryPropertyInfo = new BinaryPropertyInfo <sbyte> { Options = options, MemberInfo = memberInfo }; binaryPropertyInfo.DeterminePropertyName(); binaryPropertyInfo.IsIgnored = true; binaryPropertyInfo.TypeMap = typeMap; Debug.Assert(!binaryPropertyInfo.ShouldDeserialize); Debug.Assert(!binaryPropertyInfo.ShouldSerialize); return(binaryPropertyInfo); }
public void Reset() { CollectionEnumerator = null; EnumeratorIndex = 0; IgnoreDictionaryKeyPolicy = false; BinaryClassInfo = null !; EnumerableIndexBytes = 8; //PolymorphicBinaryClassInfo = null; PolymorphicBinaryPropertyInfo = null; OriginalDepth = 0; ProcessedStartToken = false; ProcessedEndToken = false; ProcessedEnumerableIndex = false; ObjectState = StackFrameWriteObjectState.None; //ProcessedArrayLength = false; EndProperty(); }
internal static BinaryPropertyInfo LookupProperty( object obj, ReadOnlySpan <byte> unescapedPropertyName, ref ReadStack state, out bool useExtensionProperty, bool createExtensionProperty = true) { Debug.Assert(state.Current.BinaryClassInfo.ClassType == ClassType.Object || state.Current.BinaryClassInfo.ClassType == ClassType.Enumerable || state.Current.BinaryClassInfo.ClassType == ClassType.Dictionary); useExtensionProperty = false; BinaryPropertyInfo binaryPropertyInfo = state.Current.BinaryClassInfo.GetProperty( unescapedPropertyName, ref state.Current, out byte[] utf8PropertyName); // Increment PropertyIndex so GetProperty() checks the next property first when called again. state.Current.PropertyIndex++; // For case insensitive and missing property support of BinaryPath, remember the value on the temporary stack. state.Current.BinaryPropertyName = utf8PropertyName; // Determine if we should use the extension property. if (binaryPropertyInfo == BinaryPropertyInfo.s_missingProperty) { BinaryPropertyInfo dataExtProperty = state.Current.BinaryClassInfo.DataExtensionProperty; if (dataExtProperty != null && dataExtProperty.HasGetter && dataExtProperty.HasSetter) { state.Current.BinaryPropertyNameAsString = BinaryReaderHelper.TranscodeHelper(unescapedPropertyName); if (createExtensionProperty) { CreateDataExtensionProperty(ref state, obj, dataExtProperty); } binaryPropertyInfo = dataExtProperty; useExtensionProperty = true; } } state.Current.BinaryPropertyInfo = binaryPropertyInfo; return(binaryPropertyInfo); }
private static BinaryPropertyInfo GetPropertyWithUniqueAttribute(Type classType, Type attributeType, Dictionary <string, BinaryPropertyInfo> cache) { BinaryPropertyInfo property = null; foreach (BinaryPropertyInfo binaryPropertyInfo in cache.Values) { Debug.Assert(binaryPropertyInfo.MemberInfo != null); Attribute attribute = binaryPropertyInfo.MemberInfo.GetCustomAttribute(attributeType); if (attribute != null) { if (property != null) { ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(classType, attributeType); } property = binaryPropertyInfo; } } return(property); }
/// <summary> /// 检查是否具有扩展数据字段 /// </summary> /// <param name="cache"></param> /// <returns></returns> public bool DetermineExtensionDataProperty(Dictionary <string, BinaryPropertyInfo> cache) { // 一个类型中只能由一个扩展字段(由BinaryExtensionDataAttribute标注) BinaryPropertyInfo binaryPropertyInfo = GetPropertyWithUniqueAttribute(Type, typeof(BinaryExtensionDataAttribute), cache); if (binaryPropertyInfo != null) { Type declaredPropertyType = binaryPropertyInfo.DeclaredPropertyType; if (typeof(IDictionary <string, object>).IsAssignableFrom(declaredPropertyType)) { BinaryConverter converter = Options.GetConverter(declaredPropertyType); Debug.Assert(converter != null); } else { ThrowHelper.ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(Type, binaryPropertyInfo); } DataExtensionProperty = binaryPropertyInfo; return(true); } return(false); }
public static void ThrowInvalidOperationException_SerializerPropertyNameNull(Type parentType, BinaryPropertyInfo binaryPropertyInfo) { throw new InvalidOperationException(string.Format(Strings.SerializerPropertyNameNull, parentType, binaryPropertyInfo.MemberInfo?.Name)); }
public static void ThrowInvalidOperationException_IgnoreConditionOnValueTypeInvalid(BinaryPropertyInfo binaryPropertyInfo) { MemberInfo memberInfo = binaryPropertyInfo.MemberInfo !; throw new InvalidOperationException(string.Format(Strings.IgnoreConditionOnValueTypeInvalid, memberInfo.Name, memberInfo.DeclaringType)); }
public void EndDictionaryElement() { PropertyState = StackFramePropertyState.None; PolymorphicBinaryPropertyInfo = null; }
private void GetObjectMemberInfos(Type type, TypeMap typeMap, BinaryConverter converter, bool ignoreReadOnly = false) { Dictionary <string, BinaryPropertyInfo> cache = new Dictionary <string, BinaryPropertyInfo>( Options.PropertyNameCaseInsensitive ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal); Dictionary <string, MemberInfo> ignoredMembers = null; // We start from the most derived type. for (Type currentType = type; currentType != null; currentType = currentType.BaseType) { const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; foreach (PropertyInfo propertyInfo in currentType.GetProperties(bindingFlags)) { // Ignore indexers and virtual properties that have overrides that were [BinaryIgnore]d. if (propertyInfo.GetIndexParameters().Length > 0 || PropertyIsOverridenAndIgnored(propertyInfo, ignoredMembers)) { continue; } // For now we only support public properties (i.e. setter and/or getter is public). if (propertyInfo.GetMethod?.IsPublic == true || propertyInfo.SetMethod?.IsPublic == true) { if (!propertyInfo.CanWrite && ignoreReadOnly) { continue; } CacheMember(currentType, propertyInfo.PropertyType, propertyInfo, cache, ref ignoredMembers); } else { if (BinaryPropertyInfo.GetAttribute <BinaryIncludeAttribute>(propertyInfo) != null) { ThrowHelper.ThrowInvalidOperationException_BinaryIncludeOnNonPublicInvalid(propertyInfo, currentType); } // Non-public properties should not be included for (de)serialization. } } foreach (FieldInfo fieldInfo in currentType.GetFields(bindingFlags)) { if (PropertyIsOverridenAndIgnored(fieldInfo, ignoredMembers)) { continue; } bool hasBinaryInclude = BinaryPropertyInfo.GetAttribute <BinaryIncludeAttribute>(fieldInfo) != null; if (fieldInfo.IsPublic) { if (hasBinaryInclude || Options.IncludeFields || converter.IncludeFields) { CacheMember(currentType, fieldInfo.FieldType, fieldInfo, cache, ref ignoredMembers); } } else { if (hasBinaryInclude) { ThrowHelper.ThrowInvalidOperationException_BinaryIncludeOnNonPublicInvalid(fieldInfo, currentType); } // Non-public fields should not be included for (de)serialization. } } var methods = converter.GetAdditionalDataMethod(); if (methods != null) { foreach (var m in methods) { CacheMember(currentType, m.ReturnType, m, cache, ref ignoredMembers); } } } BinaryPropertyInfo[] cacheArray; if (DetermineExtensionDataProperty(cache)) { // Remove from cache since it is handled independently. cache.Remove(DataExtensionProperty !.NameAsString); cacheArray = new BinaryPropertyInfo[cache.Count + 1]; // Set the last element to the extension property. cacheArray[cache.Count] = DataExtensionProperty; } else { cacheArray = new BinaryPropertyInfo[cache.Count]; } // Copy the dictionary cache to the array cache. cache.Values.CopyTo(cacheArray, 0); // These are not accessed by other threads until the current BinaryClassInfo instance // is finished initializing and added to the cache on BinarySerializerOptions. PropertyCache = cache; PropertyCacheArray = cacheArray; if (converter.ConstructorIsParameterized) { InitializeConstructorParameters(converter.ConstructorInfo !); } typeMap.TrySetTypeMemberInfos(TypeSeq, this.GetMemberInfos); }