/// <summary> /// Returns the ValueMember instances associated with this type /// </summary> public ValueMember[] GetFields() { ValueMember[] arr = new ValueMember[_fields.Count]; _fields.CopyTo(arr, 0); Array.Sort(arr, ValueMember.Comparer.Default); return(arr); }
/// <summary> /// Returns the SubType instances associated with this type /// </summary> public SubType[] GetSubtypes() { if (_subTypes == null || _subTypes.Count == 0) { return(new SubType[0]); } SubType[] arr = new SubType[_subTypes.Count]; _subTypes.CopyTo(arr, 0); Array.Sort(arr, SubType.Comparer.Default); return(arr); }
private bool TryDeserializeList(TypeModel model, ProtoReader reader, BinaryDataFormat format, int tag, Type listType, Type itemType, bool isRoot, ref object value) { bool isList; MethodInfo addMethod = TypeModel.ResolveListAdd(model, listType, itemType, out isList); if (addMethod == null) { throw new NotSupportedException("Unknown list variant: " + listType.FullName); } bool found = false; object nextItem = null; IList list = value as IList; object[] args = isList ? null : new object[1]; BasicList arraySurrogate = listType.IsArray ? new BasicList() : null; while (TryDeserializeAuxiliaryType(reader, format, tag, itemType, ref nextItem, true, true, true, true, isRoot)) { found = true; if (value == null && arraySurrogate == null) { value = CreateListInstance(listType, itemType); if (value != null) { ProtoReader.NoteObject(value, reader); } list = value as IList; } if (list != null) { list.Add(nextItem); } else if (arraySurrogate != null) { arraySurrogate.Add(nextItem); } else { args[0] = nextItem; addMethod.Invoke(value, args); } nextItem = null; } if (arraySurrogate != null) { Array newArray; if (value != null) { if (arraySurrogate.Count == 0) { // we'll stay with what we had, thanks } else { Array existing = (Array)value; newArray = Array.CreateInstance(itemType, existing.Length + arraySurrogate.Count); Array.Copy(existing, newArray, existing.Length); arraySurrogate.CopyTo(newArray, existing.Length); value = newArray; } } else { newArray = Array.CreateInstance(itemType, arraySurrogate.Count); arraySurrogate.CopyTo(newArray, 0); value = newArray; ProtoReader.NoteObject(value, reader); } } return(found); }
/// <summary> /// Suggest a .proto definition for the given type /// </summary> /// <param name="type">The type to generate a .proto definition for, or <c>null</c> to generate a .proto that represents the entire model</param> /// <returns>The .proto definition as a string</returns> public override string GetSchema(Type type) { BasicList requiredTypes = new BasicList(); MetaType primaryType = null; bool isInbuiltType = false; if (type == null) { // generate for the entire model for (int i = _serviceTypesCount; i < _types.Count; i++) { MetaType meta = (MetaType)_types[i]; MetaType tmp = meta.GetSurrogateOrBaseOrSelf(false); if (!requiredTypes.Contains(tmp)) { // ^^^ note that the type might have been added as a descendent requiredTypes.Add(tmp); CascadeDependents(requiredTypes, tmp); } } } else { Type tmp = Helpers.GetNullableUnderlyingType(type); if (tmp != null) { type = tmp; } WireType defaultWireType; isInbuiltType = (this.ValueSerializerBuilder.TryGetSimpleCoreSerializer(BinaryDataFormat.Default, type, out defaultWireType) != null); if (!isInbuiltType) { //Agenerate just relative to the supplied type int index = FindOrAddAuto(type, false, false, false); if (index < 0) { throw new ArgumentException("The type specified is not a contract-type", nameof(type)); } // get the required types primaryType = ((MetaType)_types[index]).GetSurrogateOrBaseOrSelf(false); requiredTypes.Add(primaryType); CascadeDependents(requiredTypes, primaryType); } } // use the provided type's namespace for the "package" StringBuilder headerBuilder = new StringBuilder(); string package = null; if (!isInbuiltType) { IEnumerable typesForNamespace = primaryType == null ? (IEnumerable)MetaTypes : requiredTypes; foreach (MetaType meta in typesForNamespace) { meta.FinalizeSettingsValue(); if (meta.IsList) { continue; } string tmp = meta.Type.Namespace; if (!Helpers.IsNullOrEmpty(tmp)) { if (tmp.StartsWith("System.", StringComparison.Ordinal)) { continue; } if (package == null) { // haven't seen any suggestions yet package = tmp; } else if (package == tmp) { // that's fine; a repeat of the one we already saw } else { // something else; have confliucting suggestions; abort package = null; break; } } } } if (!Helpers.IsNullOrEmpty(package)) { headerBuilder.Append("package ").Append(package).Append(';'); Helpers.AppendLine(headerBuilder); } bool requiresBclImport = false; StringBuilder bodyBuilder = new StringBuilder(); // sort them by schema-name MetaType[] metaTypesArr = new MetaType[requiredTypes.Count]; requiredTypes.CopyTo(metaTypesArr, 0); Array.Sort(metaTypesArr, MetaType.Comparer.Default); // write the messages if (isInbuiltType) { Helpers.AppendLine(bodyBuilder).Append("message ").Append(type.Name).Append(" {"); MetaType.NewLine(bodyBuilder, 1).Append("optional ").Append(GetSchemaTypeName(type, BinaryDataFormat.Default, false, false, ref requiresBclImport)) .Append(" value = 1;"); Helpers.AppendLine(bodyBuilder).Append('}'); } else { for (int i = 0; i < metaTypesArr.Length; i++) { MetaType tmp = metaTypesArr[i]; if (tmp.IsList && tmp != primaryType) { continue; } tmp.WriteSchema(bodyBuilder, 0, ref requiresBclImport); } } if (requiresBclImport) { headerBuilder.Append("import \"bcl.proto\"; // schema for protobuf-net's handling of core .NET types"); Helpers.AppendLine(headerBuilder); } return(Helpers.AppendLine(headerBuilder.Append(bodyBuilder)).ToString()); }
private void WriteGetKeyImpl(TypeBuilder type, bool hasInheritance, SerializerPair[] methodPairs, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName, out ILGenerator il, out int knownTypesCategory, out FieldBuilder knownTypes, out Type knownTypesLookupType) { var genInfo = Override(type, "GetKeyImpl"); il = genInfo.GetILGenerator(); Compiler.CompilerContext ctx = new Compiler.CompilerContext(genInfo, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(System.Type), true)); if (_types.Count <= KnownTypes_ArrayCutoff) { knownTypesCategory = KnownTypes_Array; knownTypesLookupType = MapType(typeof(System.Type[]), true); } else { #if NO_GENERICS knownTypesLookupType = null; #else knownTypesLookupType = MapType(typeof(System.Collections.Generic.Dictionary <System.Type, int>), false); #endif if (knownTypesLookupType == null) { knownTypesLookupType = MapType(typeof(Hashtable), true); knownTypesCategory = KnownTypes_Hashtable; } else { knownTypesCategory = KnownTypes_Dictionary; } } knownTypes = type.DefineField("knownTypes", knownTypesLookupType, FieldAttributes.Private | FieldAttributes.InitOnly | FieldAttributes.Static); switch (knownTypesCategory) { case KnownTypes_Array: { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); // note that Array.IndexOf is not supported under CF il.EmitCall(OpCodes.Callvirt, MapType(typeof(IList)).GetMethod( "IndexOf", new Type[] { MapType(typeof(object)) }), null); if (hasInheritance) { il.DeclareLocal(MapType(typeof(int))); // loc-0 il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc_0); BasicList getKeyLabels = new BasicList(); int lastKey = -1; for (int i = 0; i < methodPairs.Length; i++) { if (methodPairs[i].MetaKey == methodPairs[i].BaseKey) { break; } if (lastKey == methodPairs[i].BaseKey) { // add the last label again getKeyLabels.Add(getKeyLabels[getKeyLabels.Count - 1]); } else { // add a new unique label getKeyLabels.Add(ctx.DefineLabel()); lastKey = methodPairs[i].BaseKey; } } Compiler.CodeLabel[] subtypeLabels = new Compiler.CodeLabel[getKeyLabels.Count]; getKeyLabels.CopyTo(subtypeLabels, 0); ctx.Switch(subtypeLabels); il.Emit(OpCodes.Ldloc_0); // not a sub-type; use the original value il.Emit(OpCodes.Ret); lastKey = -1; // now output the different branches per sub-type (not derived type) for (int i = subtypeLabels.Length - 1; i >= 0; i--) { if (lastKey != methodPairs[i].BaseKey) { lastKey = methodPairs[i].BaseKey; // find the actual base-index for this base-key (i.e. the index of // the base-type) int keyIndex = -1; for (int j = subtypeLabels.Length; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } ctx.MarkLabel(subtypeLabels[i]); Compiler.CompilerContext.LoadValue(il, keyIndex); il.Emit(OpCodes.Ret); } } } else { il.Emit(OpCodes.Ret); } } break; case KnownTypes_Dictionary: { LocalBuilder result = il.DeclareLocal(MapType(typeof(int))); Label otherwise = il.DefineLabel(); il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloca_S, result); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("TryGetValue", BindingFlags.Instance | BindingFlags.Public), null); il.Emit(OpCodes.Brfalse_S, otherwise); il.Emit(OpCodes.Ldloc_S, result); il.Emit(OpCodes.Ret); il.MarkLabel(otherwise); il.Emit(OpCodes.Ldc_I4_M1); il.Emit(OpCodes.Ret); } break; case KnownTypes_Hashtable: { Label otherwise = il.DefineLabel(); il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetProperty("Item").GetGetMethod(), null); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, otherwise); #if FX11 il.Emit(OpCodes.Unbox, MapType(typeof(int))); il.Emit(OpCodes.Ldobj, MapType(typeof(int))); #else if (ilVersion == Compiler.CompilerContext.ILVersion.Net1) { il.Emit(OpCodes.Unbox, MapType(typeof(int))); il.Emit(OpCodes.Ldobj, MapType(typeof(int))); } else { il.Emit(OpCodes.Unbox_Any, MapType(typeof(int))); } #endif il.Emit(OpCodes.Ret); il.MarkLabel(otherwise); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldc_I4_M1); il.Emit(OpCodes.Ret); } break; default: throw new InvalidOperationException(); } }
public static ConstructorInfo ResolveTupleConstructor(Type type, out MemberInfo[] mappedMembers) { mappedMembers = null; if (type == null) { throw new ArgumentNullException(nameof(type)); } #if WINRT TypeInfo typeInfo = type.GetTypeInfo(); if (typeInfo.IsAbstract) { return(null); // as if! } ConstructorInfo[] ctors = Helpers.GetConstructors(typeInfo, false); #else if (type.IsAbstract) { return(null); // as if! } ConstructorInfo[] ctors = Helpers.GetConstructors(type, false); #endif // need to have an interesting constructor to bother even checking this stuff if (ctors.Length == 0 || (ctors.Length == 1 && ctors[0].GetParameters().Length == 0)) { return(null); } MemberInfo[] fieldsPropsUnfiltered = Helpers.GetInstanceFieldsAndProperties(type, true); BasicList memberList = new BasicList(); for (int i = 0; i < fieldsPropsUnfiltered.Length; i++) { PropertyInfo prop = fieldsPropsUnfiltered[i] as PropertyInfo; if (prop != null) { if (!prop.CanRead) { return(null); // no use if can't read } if (prop.CanWrite && Helpers.GetSetMethod(prop, false, false) != null) { return(null); // don't allow a public set (need to allow non-public to handle Mono's KeyValuePair<,>) } memberList.Add(prop); } else { FieldInfo field = fieldsPropsUnfiltered[i] as FieldInfo; if (field != null) { if (!field.IsInitOnly) { return(null); // all public fields must be readonly to be counted a tuple } memberList.Add(field); } } } if (memberList.Count == 0) { return(null); } MemberInfo[] members = new MemberInfo[memberList.Count]; memberList.CopyTo(members, 0); int[] mapping = new int[members.Length]; int found = 0; ConstructorInfo result = null; mappedMembers = new MemberInfo[mapping.Length]; for (int i = 0; i < ctors.Length; i++) { ParameterInfo[] parameters = ctors[i].GetParameters(); if (parameters.Length != members.Length) { continue; } // reset the mappings to test for (int j = 0; j < mapping.Length; j++) { mapping[j] = -1; } for (int j = 0; j < parameters.Length; j++) { for (int k = 0; k < members.Length; k++) { if (string.Compare(parameters[j].Name, members[k].Name, StringComparison.OrdinalIgnoreCase) != 0) { continue; } Type memberType = Helpers.GetMemberType(members[k]); if (memberType != parameters[j].ParameterType) { continue; } mapping[j] = k; } } // did we map all? bool notMapped = false; for (int j = 0; j < mapping.Length; j++) { if (mapping[j] < 0) { notMapped = true; break; } mappedMembers[j] = members[mapping[j]]; } if (notMapped) { continue; } found++; result = ctors[i]; } return(found == 1 ? result : null); }