internal static bool TryGetTag(MemberInfo member, out int tag, out string name, bool callerIsTagInference, out DataFormat format, out MemberSerializationOptions options) { name = member.Name; format = DataFormat.Default; tag = -1; options = MemberSerializationOptions.None; // check for delegates (don't even try!) Type valueType; switch (member.MemberType) { case MemberTypes.Property: valueType = ((PropertyInfo)member).PropertyType; break; case MemberTypes.Field: valueType = ((FieldInfo)member).FieldType; break; default: // not sure what this is! return(false); } if (valueType.IsSubclassOf(typeof(Delegate))) { return(false); } // check for exclusion if (AttributeUtils.GetAttribute <ProtoIgnoreAttribute>(member) != null || AttributeUtils.GetAttribute <ProtoPartialIgnoreAttribute>(member.ReflectedType, delegate(ProtoPartialIgnoreAttribute ppia) { return(ppia.MemberName == member.Name); }) != null) { return(false); } // check against the property ProtoMemberAttribute pm = AttributeUtils.GetAttribute <ProtoMemberAttribute>(member); if (pm == null) { // check also against the type pm = AttributeUtils.GetAttribute <ProtoPartialMemberAttribute>(member.ReflectedType, delegate(ProtoPartialMemberAttribute ppma) { return(ppma.MemberName == member.Name); }); } if (pm != null) { format = pm.DataFormat; if (!string.IsNullOrEmpty(pm.Name)) { name = pm.Name; } tag = pm.Tag; options = pm.Options; return(tag > 0); } ProtoContractAttribute pca = AttributeUtils.GetAttribute <ProtoContractAttribute>(member.DeclaringType); if (pca != null && pca.ImplicitFields != ImplicitFields.None) { if (callerIsTagInference) { return(true); // short-circuit } List <MemberInfo> members = new List <MemberInfo>(); switch (pca.ImplicitFields) { case ImplicitFields.AllFields: AddImplicitByDeclaringType(member.DeclaringType, members, member.DeclaringType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); break; case ImplicitFields.AllPublic: AddImplicitByDeclaringType(member.DeclaringType, members, member.DeclaringType.GetFields(BindingFlags.Instance | BindingFlags.Public)); AddImplicitByDeclaringType(member.DeclaringType, members, member.DeclaringType.GetProperties(BindingFlags.Instance | BindingFlags.Public)); break; default: throw new NotSupportedException("Unknown ImplicitFields option: " + pca.ImplicitFields); } members.Sort(delegate(MemberInfo x, MemberInfo y) { return(string.CompareOrdinal(x.Name, y.Name)); }); int index = members.IndexOf(member); if (index >= 0) { tag = index + pca.ImplicitFirstTag; return(true); } return(false); } XmlElementAttribute xe = AttributeUtils.GetAttribute <XmlElementAttribute>(member); if (xe != null) { if (!string.IsNullOrEmpty(xe.ElementName)) { name = xe.ElementName; } tag = xe.Order; return(tag > 0); } XmlArrayAttribute xa = AttributeUtils.GetAttribute <XmlArrayAttribute>(member); if (xa != null) { if (!string.IsNullOrEmpty(xa.ElementName)) { name = xa.ElementName; } tag = xa.Order; return(tag > 0); } return(false); }
internal static bool HasOption(MemberSerializationOptions options, MemberSerializationOptions required) { return((options & required) == required); }
/// <summary> /// Supports various different property metadata patterns: /// [ProtoMember] is the most specific, allowing the data-format to be set. /// [DataMember], [XmlElement] are supported for compatibility. /// In any event, there must be a unique positive Tag/Order. /// </summary> internal static bool TryGetTag(MemberInfo member, out int tag, out string name, out DataFormat format, out MemberSerializationOptions options) { return(TryGetTag(member, out tag, out name, false, out format, out options)); }
/// <summary> /// Responsible for deciding how to encode/decode a given data-type; maybe /// not the most elegant solution, but it is simple and quick. /// </summary> private static Property <T> CreateProperty <T>(Type type, ref DataFormat format, MemberSerializationOptions options) { if (type == typeof(int)) { switch (format) { case DataFormat.Default: case DataFormat.TwosComplement: format = DataFormat.TwosComplement; return(new PropertyInt32Variant <T>()); case DataFormat.ZigZag: return(new PropertyInt32ZigZag <T>()); case DataFormat.FixedSize: return(new PropertyInt32Fixed <T>()); } } if (type == typeof(long)) { switch (format) { case DataFormat.Default: case DataFormat.TwosComplement: format = DataFormat.TwosComplement; return(new PropertyInt64Variant <T>()); case DataFormat.ZigZag: return(new PropertyInt64ZigZag <T>()); case DataFormat.FixedSize: return(new PropertyInt64Fixed <T>()); } } if (type == typeof(uint)) { switch (format) { case DataFormat.Default: case DataFormat.TwosComplement: format = DataFormat.TwosComplement; return(new PropertyUInt32Variant <T>()); case DataFormat.FixedSize: return(new PropertyUInt32Fixed <T>()); } } if (type == typeof(ulong)) { switch (format) { case DataFormat.Default: case DataFormat.TwosComplement: format = DataFormat.TwosComplement; return(new PropertyUInt64Variant <T>()); case DataFormat.FixedSize: return(new PropertyUInt64Fixed <T>()); } } if (type == typeof(short)) { switch (format) { case DataFormat.Default: case DataFormat.TwosComplement: format = DataFormat.TwosComplement; return(new PropertyInt16Variant <T>()); case DataFormat.ZigZag: return(new PropertyInt16ZigZag <T>()); } } if (type == typeof(byte[])) { format = DataFormat.Default; return(new PropertyBlob <T>()); } if (type == typeof(byte)) { format = DataFormat.TwosComplement; return(new PropertyByte <T>()); } if (type == typeof(sbyte)) { format = DataFormat.ZigZag; return(new PropertySByte <T>()); } if (type == typeof(char)) { format = DataFormat.TwosComplement; return(new PropertyChar <T>()); } if (type == typeof(bool)) { format = DataFormat.TwosComplement; return(new PropertyBoolean <T>()); } if (type == typeof(string)) { format = DataFormat.Default; return(new PropertyString <T>()); } if (type == typeof(float)) { format = DataFormat.FixedSize; return(new PropertySingle <T>()); } if (type == typeof(double)) { format = DataFormat.FixedSize; return(new PropertyDouble <T>()); } if (type == typeof(Uri)) { format = DataFormat.Default; return(new PropertyUri <T>()); } if (type == typeof(Guid)) { switch (format) { case DataFormat.Group: return(new PropertyGuidGroup <T>()); case DataFormat.Default: return(new PropertyGuidString <T>()); } } if (type == typeof(TimeSpan)) { switch (format) { case DataFormat.Group: return(new PropertyTimeSpanGroup <T>()); case DataFormat.Default: return(new PropertyTimeSpanString <T>()); case DataFormat.FixedSize: return(new PropertyTimeSpanFixed <T>()); } } if (type == typeof(DateTime)) { switch (format) { case DataFormat.Group: return(new PropertyDateTimeGroup <T>()); case DataFormat.Default: return(new PropertyDateTimeString <T>()); case DataFormat.FixedSize: return(new PropertyDateTimeFixed <T>()); } } if (type == typeof(decimal)) { switch (format) { case DataFormat.Group: return(new PropertyDecimalGroup <T>()); case DataFormat.Default: return(new PropertyDecimalString <T>()); } } if (Serializer.IsEntityType(type)) { Type baseType = type; while (Serializer.IsEntityType(baseType.BaseType)) { baseType = baseType.BaseType; } switch (format) { case DataFormat.Default: return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyMessageString", type, baseType, baseType)); case DataFormat.Group: return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyMessageGroup", type, baseType, baseType)); } } if (type.IsEnum) { format = DataFormat.TwosComplement; return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyEnum", type)); } if (type.IsValueType && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair <,>)) { return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyPairString", type.GetGenericArguments())); } bool isEnumerableOnly; Type listItemType = GetListType(type, out isEnumerableOnly); if (type.IsArray) { // verify that we can handle it if (type.GetArrayRank() != 1) { throw new NotSupportedException("Only 1-dimensional arrays can be used; consider an array/list of a class-type instead"); } } if (listItemType != null && listItemType != typeof(byte[])) { bool dummy; if (GetListType(listItemType, out dummy) != null) { throw new NotSupportedException("Nested (jagged) arrays/lists are not supported (except for byte[]); consider an array/list of a class-type with an inner array/list instead"); } } if (type == typeof(byte[])) { // want to treat byte[] as a special case listItemType = null; } if (type.IsArray && listItemType != null) // second check is for byte[] { return(PropertyUtil <T> .CreateTypedProperty( (PropertyFactory.HasOption(options, MemberSerializationOptions.Packed) ? "CreatePropertyPackedArray" : "CreatePropertyArray"), listItemType)); } if (listItemType != null) { if (isEnumerableOnly) { if (GetAddMethod(type, listItemType) != null) { return(PropertyUtil <T> .CreateTypedProperty( (PropertyFactory.HasOption(options, MemberSerializationOptions.Packed) ? "CreatePropertyPackedEnumerable" : "CreatePropertyEnumerable"), type, listItemType)); } } else { return(PropertyUtil <T> .CreateTypedProperty( (PropertyFactory.HasOption(options, MemberSerializationOptions.Packed) ? "CreatePropertyPackedList" : "CreatePropertyList"), type, listItemType)); } } Type nullType = Nullable.GetUnderlyingType(type); if (nullType != null) { return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyNullable", nullType)); } if (format == DataFormat.Default && GetParseMethod(type) != null) { return(PropertyUtil <T> .CreateTypedProperty("CreatePropertyParseable", type)); } throw Serializer.ThrowNoEncoder(format, type); }