12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066 |
- #if !NO_RUNTIME
- using System;
- using System.Collections;
- using System.Text;
- #if FEAT_IKVM
- using Type = IKVM.Reflection.Type;
- using IKVM.Reflection;
- using IKVM.Reflection.Emit;
- #else
- using System.Reflection;
- #if FEAT_COMPILER
- using System.Reflection.Emit;
- #endif
- #endif
- using ProtoBuf.Serializers;
- using System.Threading;
- using System.IO;
- namespace ProtoBuf.Meta
- {
- /// <summary>
- /// Provides protobuf serialization support for a number of types that can be defined at runtime
- /// </summary>
- public sealed class RuntimeTypeModel : TypeModel
- {
- private ushort options;
- private const ushort
- OPTIONS_InferTagFromNameDefault = 1,
- OPTIONS_IsDefaultModel = 2,
- OPTIONS_Frozen = 4,
- OPTIONS_AutoAddMissingTypes = 8,
- #if FEAT_COMPILER && !FX11
- OPTIONS_AutoCompile = 16,
- #endif
- OPTIONS_UseImplicitZeroDefaults = 32,
- OPTIONS_AllowParseableTypes = 64,
- OPTIONS_AutoAddProtoContractTypesOnly = 128,
- OPTIONS_IncludeDateTimeKind = 256;
- private bool GetOption(ushort option)
- {
- return (options & option) == option;
- }
- private void SetOption(ushort option, bool value)
- {
- if (value) options |= option;
- else options &= (ushort)~option;
- }
- /// <summary>
- /// Global default that
- /// enables/disables automatic tag generation based on the existing name / order
- /// of the defined members. See <seealso cref="ProtoContractAttribute.InferTagFromName"/>
- /// for usage and <b>important warning</b> / explanation.
- /// You must set the global default before attempting to serialize/deserialize any
- /// impacted type.
- /// </summary>
- public bool InferTagFromNameDefault
- {
- get { return GetOption(OPTIONS_InferTagFromNameDefault); }
- set { SetOption(OPTIONS_InferTagFromNameDefault, value); }
- }
- /// <summary>
- /// Global default that determines whether types are considered serializable
- /// if they have [DataContract] / [XmlType]. With this enabled, <b>ONLY</b>
- /// types marked as [ProtoContract] are added automatically.
- /// </summary>
- public bool AutoAddProtoContractTypesOnly
- {
- get { return GetOption(OPTIONS_AutoAddProtoContractTypesOnly); }
- set { SetOption(OPTIONS_AutoAddProtoContractTypesOnly, value); }
- }
- /// <summary>
- /// Global switch that enables or disables the implicit
- /// handling of "zero defaults"; meanning: if no other default is specified,
- /// it assumes bools always default to false, integers to zero, etc.
- ///
- /// If this is disabled, no such assumptions are made and only *explicit*
- /// default values are processed. This is enabled by default to
- /// preserve similar logic to v1.
- /// </summary>
- public bool UseImplicitZeroDefaults
- {
- get {return GetOption(OPTIONS_UseImplicitZeroDefaults);}
- set {
- if (!value && GetOption(OPTIONS_IsDefaultModel))
- {
- throw new InvalidOperationException("UseImplicitZeroDefaults cannot be disabled on the default model");
- }
- SetOption(OPTIONS_UseImplicitZeroDefaults, value);
- }
- }
- /// <summary>
- /// Global switch that determines whether types with a <c>.ToString()</c> and a <c>Parse(string)</c>
- /// should be serialized as strings.
- /// </summary>
- public bool AllowParseableTypes
- {
- get { return GetOption(OPTIONS_AllowParseableTypes); }
- set { SetOption(OPTIONS_AllowParseableTypes, value); }
- }
- /// <summary>
- /// Global switch that determines whether DateTime serialization should include the <c>Kind</c> of the date/time.
- /// </summary>
- public bool IncludeDateTimeKind
- {
- get { return GetOption(OPTIONS_IncludeDateTimeKind); }
- set { SetOption(OPTIONS_IncludeDateTimeKind, value); }
- }
- /// <summary>
- /// Should the <c>Kind</c> be included on date/time values?
- /// </summary>
- protected internal override bool SerializeDateTimeKind()
- {
- return GetOption(OPTIONS_IncludeDateTimeKind);
- }
-
- private sealed class Singleton
- {
- private Singleton() { }
- internal static readonly RuntimeTypeModel Value = new RuntimeTypeModel(true);
- }
- /// <summary>
- /// The default model, used to support ProtoBuf.Serializer
- /// </summary>
- public static RuntimeTypeModel Default
- {
- get { return Singleton.Value; }
- }
- /// <summary>
- /// Returns a sequence of the Type instances that can be
- /// processed by this model.
- /// </summary>
- public IEnumerable GetTypes() { return types; }
- /// <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
- foreach(MetaType meta in types)
- {
- 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.GetUnderlyingType(type);
- if (tmp != null) type = tmp;
- WireType defaultWireType;
- isInbuiltType = (ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out defaultWireType, false, false, false, false) != 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", "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 ? types : requiredTypes;
- foreach (MetaType meta in typesForNamespace)
- {
- if (meta.IsList) continue;
- string tmp = meta.Type.Namespace;
- if (!Helpers.IsNullOrEmpty(tmp))
- {
- if (tmp.StartsWith("System.")) 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, DataFormat.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 CascadeDependents(BasicList list, MetaType metaType)
- {
- MetaType tmp;
- if (metaType.IsList)
- {
- Type itemType = TypeModel.GetListItemType(this, metaType.Type);
- WireType defaultWireType;
- IProtoSerializer coreSerializer = ValueMember.TryGetCoreSerializer(this, DataFormat.Default, itemType, out defaultWireType, false, false, false, false);
- if (coreSerializer == null)
- {
- int index = FindOrAddAuto(itemType, false, false, false);
- if (index >= 0)
- {
- tmp = ((MetaType)types[index]).GetSurrogateOrBaseOrSelf(false);
- if (!list.Contains(tmp))
- { // could perhaps also implement as a queue, but this should work OK for sane models
- list.Add(tmp);
- CascadeDependents(list, tmp);
- }
- }
- }
- }
- else
- {
- if (metaType.IsAutoTuple)
- {
- MemberInfo[] mapping;
- if(MetaType.ResolveTupleConstructor(metaType.Type, out mapping) != null)
- {
- for (int i = 0; i < mapping.Length; i++)
- {
- Type type = null;
- if (mapping[i] is PropertyInfo) type = ((PropertyInfo)mapping[i]).PropertyType;
- else if (mapping[i] is FieldInfo) type = ((FieldInfo)mapping[i]).FieldType;
- WireType defaultWireType;
- IProtoSerializer coreSerializer = ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out defaultWireType, false, false, false, false);
- if (coreSerializer == null)
- {
- int index = FindOrAddAuto(type, false, false, false);
- if (index >= 0)
- {
- tmp = ((MetaType)types[index]).GetSurrogateOrBaseOrSelf(false);
- if (!list.Contains(tmp))
- { // could perhaps also implement as a queue, but this should work OK for sane models
- list.Add(tmp);
- CascadeDependents(list, tmp);
- }
- }
- }
- }
- }
- }
- else
- {
- foreach (ValueMember member in metaType.Fields)
- {
- Type type = member.ItemType;
- if (type == null) type = member.MemberType;
- WireType defaultWireType;
- IProtoSerializer coreSerializer = ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out defaultWireType, false, false, false, false);
- if (coreSerializer == null)
- {
- // is an interesting type
- int index = FindOrAddAuto(type, false, false, false);
- if (index >= 0)
- {
- tmp = ((MetaType)types[index]).GetSurrogateOrBaseOrSelf(false);
- if (!list.Contains(tmp))
- { // could perhaps also implement as a queue, but this should work OK for sane models
- list.Add(tmp);
- CascadeDependents(list, tmp);
- }
- }
- }
- }
- }
- if (metaType.HasSubtypes)
- {
- foreach (SubType subType in metaType.GetSubtypes())
- {
- tmp = subType.DerivedType.GetSurrogateOrSelf(); // note: exclude base-types!
- if (!list.Contains(tmp))
- {
- list.Add(tmp);
- CascadeDependents(list, tmp);
- }
- }
- }
- tmp = metaType.BaseType;
- if (tmp != null) tmp = tmp.GetSurrogateOrSelf(); // note: already walking base-types; exclude base
- if (tmp != null && !list.Contains(tmp))
- {
- list.Add(tmp);
- CascadeDependents(list, tmp);
- }
- }
- }
- internal RuntimeTypeModel(bool isDefault)
- {
- #if FEAT_IKVM
- universe = new IKVM.Reflection.Universe();
- universe.EnableMissingMemberResolution(); // needed to avoid TypedReference issue on WinRT
- #endif
- AutoAddMissingTypes = true;
- UseImplicitZeroDefaults = true;
- SetOption(OPTIONS_IsDefaultModel, isDefault);
- #if FEAT_COMPILER && !FX11 && !DEBUG
- AutoCompile = true;
- #endif
- }
- #if FEAT_IKVM
- readonly IKVM.Reflection.Universe universe;
- /// <summary>
- /// Load an assembly into the model's universe
- /// </summary>
- public Assembly Load(string path)
- {
- return universe.LoadFile(path);
- }
- /// <summary>
- /// Gets the IKVM Universe that relates to this model
- /// </summary>
- public Universe Universe { get { return universe; } }
- /// <summary>
- /// Adds support for an additional type in this model, optionally
- /// applying inbuilt patterns. If the type is already known to the
- /// model, the existing type is returned **without** applying
- /// any additional behaviour.
- /// </summary>
- public MetaType Add(string assemblyQualifiedTypeName, bool applyDefaults)
- {
- Type type = universe.GetType(assemblyQualifiedTypeName, true);
- return Add(type, applyDefaults);
- }
- /// <summary>
- /// Adds support for an additional type in this model, optionally
- /// applying inbuilt patterns. If the type is already known to the
- /// model, the existing type is returned **without** applying
- /// any additional behaviour.
- /// </summary>
- public MetaType Add(System.Type type, bool applyDefaultBehaviour)
- {
- return Add(MapType(type), applyDefaultBehaviour);
- }
- /// <summary>
- /// Obtains the MetaType associated with a given Type for the current model,
- /// allowing additional configuration.
- /// </summary>
- public MetaType this[System.Type type] { get { return this[MapType(type)]; } }
-
- #endif
- /// <summary>
- /// Obtains the MetaType associated with a given Type for the current model,
- /// allowing additional configuration.
- /// </summary>
- public MetaType this[Type type] { get { return (MetaType)types[FindOrAddAuto(type, true, false, false)]; } }
-
- internal MetaType FindWithoutAdd(Type type)
- {
- // this list is thread-safe for reading
- foreach (MetaType metaType in types)
- {
- if (metaType.Type == type)
- {
- if (metaType.Pending) WaitOnLock(metaType);
- return metaType;
- }
- }
- // if that failed, check for a proxy
- Type underlyingType = ResolveProxies(type);
- return underlyingType == null ? null : FindWithoutAdd(underlyingType);
- }
- static readonly BasicList.MatchPredicate
- MetaTypeFinder = new BasicList.MatchPredicate(MetaTypeFinderImpl),
- BasicTypeFinder = new BasicList.MatchPredicate(BasicTypeFinderImpl);
- static bool MetaTypeFinderImpl(object value, object ctx)
- {
- return ((MetaType)value).Type == (Type)ctx;
- }
- static bool BasicTypeFinderImpl(object value, object ctx)
- {
- return ((BasicType)value).Type == (Type)ctx;
- }
- private void WaitOnLock(MetaType type)
- {
- int opaqueToken = 0;
- try
- {
- TakeLock(ref opaqueToken);
- }
- finally
- {
- ReleaseLock(opaqueToken);
- }
- }
- BasicList basicTypes = new BasicList();
- sealed class BasicType
- {
- private readonly Type type;
- public Type Type { get { return type; } }
- private readonly IProtoSerializer serializer;
- public IProtoSerializer Serializer { get { return serializer; } }
- public BasicType(Type type, IProtoSerializer serializer)
- {
- this.type = type;
- this.serializer = serializer;
- }
- }
- internal IProtoSerializer TryGetBasicTypeSerializer(Type type)
- {
- int idx = basicTypes.IndexOf(BasicTypeFinder, type);
- if (idx >= 0) return ((BasicType)basicTypes[idx]).Serializer;
- lock(basicTypes)
- { // don't need a full model lock for this
- // double-checked
- idx = basicTypes.IndexOf(BasicTypeFinder, type);
- if (idx >= 0) return ((BasicType)basicTypes[idx]).Serializer;
- WireType defaultWireType;
- MetaType.AttributeFamily family = MetaType.GetContractFamily(this, type, null);
- IProtoSerializer ser = family == MetaType.AttributeFamily.None
- ? ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out defaultWireType, false, false, false, false)
- : null;
- if(ser != null) basicTypes.Add(new BasicType(type, ser));
- return ser;
- }
- }
- internal int FindOrAddAuto(Type type, bool demand, bool addWithContractOnly, bool addEvenIfAutoDisabled)
- {
- int key = types.IndexOf(MetaTypeFinder, type);
- MetaType metaType;
- // the fast happy path: meta-types we've already seen
- if (key >= 0)
- {
- metaType = (MetaType)types[key];
- if (metaType.Pending)
- {
- WaitOnLock(metaType);
- }
- return key;
- }
- // the fast fail path: types that will never have a meta-type
- bool shouldAdd = AutoAddMissingTypes || addEvenIfAutoDisabled;
- if (!Helpers.IsEnum(type) && TryGetBasicTypeSerializer(type) != null)
- {
- if (shouldAdd && !addWithContractOnly) throw MetaType.InbuiltType(type);
- return -1; // this will never be a meta-type
- }
- // otherwise: we don't yet know
- // check for proxy types
- Type underlyingType = ResolveProxies(type);
- if (underlyingType != null)
- {
- key = types.IndexOf(MetaTypeFinder, underlyingType);
- type = underlyingType; // if new added, make it reflect the underlying type
- }
- if (key < 0)
- {
- int opaqueToken = 0;
- try
- {
- TakeLock(ref opaqueToken);
- // try to recognise a few familiar patterns...
- if ((metaType = RecogniseCommonTypes(type)) == null)
- { // otherwise, check if it is a contract
- MetaType.AttributeFamily family = MetaType.GetContractFamily(this, type, null);
- if (family == MetaType.AttributeFamily.AutoTuple)
- {
- shouldAdd = addEvenIfAutoDisabled = true; // always add basic tuples, such as KeyValuePair
- }
- if (!shouldAdd || (
- !Helpers.IsEnum(type) && addWithContractOnly && family == MetaType.AttributeFamily.None)
- )
- {
- if (demand) ThrowUnexpectedType(type);
- return key;
- }
- metaType = Create(type);
- }
- metaType.Pending = true;
- bool weAdded = false;
- // double-checked
- int winner = types.IndexOf(MetaTypeFinder, type);
- if (winner < 0)
- {
- ThrowIfFrozen();
- key = types.Add(metaType);
- weAdded = true;
- }
- else
- {
- key = winner;
- }
- if (weAdded)
- {
- metaType.ApplyDefaultBehaviour();
- metaType.Pending = false;
- }
- }
- finally
- {
- ReleaseLock(opaqueToken);
- }
- }
- return key;
- }
- private MetaType RecogniseCommonTypes(Type type)
- {
- //#if !NO_GENERICS
- // if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.KeyValuePair<,>))
- // {
- // MetaType mt = new MetaType(this, type);
- // Type surrogate = typeof (KeyValuePairSurrogate<,>).MakeGenericType(type.GetGenericArguments());
- // mt.SetSurrogate(surrogate);
- // mt.IncludeSerializerMethod = false;
- // mt.Freeze();
- // MetaType surrogateMeta = (MetaType)types[FindOrAddAuto(surrogate, true, true, true)]; // this forcibly adds it if needed
- // if(surrogateMeta.IncludeSerializerMethod)
- // { // don't blindly set - it might be frozen
- // surrogateMeta.IncludeSerializerMethod = false;
- // }
- // surrogateMeta.Freeze();
- // return mt;
- // }
- //#endif
- return null;
- }
- private MetaType Create(Type type)
- {
- ThrowIfFrozen();
- return new MetaType(this, type, defaultFactory);
- }
- /// <summary>
- /// Adds support for an additional type in this model, optionally
- /// applying inbuilt patterns. If the type is already known to the
- /// model, the existing type is returned **without** applying
- /// any additional behaviour.
- /// </summary>
- /// <remarks>Inbuilt patterns include:
- /// [ProtoContract]/[ProtoMember(n)]
- /// [DataContract]/[DataMember(Order=n)]
- /// [XmlType]/[XmlElement(Order=n)]
- /// [On{Des|S}erializ{ing|ed}]
- /// ShouldSerialize*/*Specified
- /// </remarks>
- /// <param name="type">The type to be supported</param>
- /// <param name="applyDefaultBehaviour">Whether to apply the inbuilt configuration patterns (via attributes etc), or
- /// just add the type with no additional configuration (the type must then be manually configured).</param>
- /// <returns>The MetaType representing this type, allowing
- /// further configuration.</returns>
- public MetaType Add(Type type, bool applyDefaultBehaviour)
- {
- if (type == null) throw new ArgumentNullException("type");
- MetaType newType = FindWithoutAdd(type);
- if (newType != null) return newType; // return existing
- int opaqueToken = 0;
- #if WINRT || COREFX
- System.Reflection.TypeInfo typeInfo = System.Reflection.IntrospectionExtensions.GetTypeInfo(type);
- if (typeInfo.IsInterface && MetaType.ienumerable.IsAssignableFrom(typeInfo)
- #else
- if (type.IsInterface && MapType(MetaType.ienumerable).IsAssignableFrom(type)
- #endif
- && GetListItemType(this, type) == null)
- {
- throw new ArgumentException("IEnumerable[<T>] data cannot be used as a meta-type unless an Add method can be resolved");
- }
- try
- {
- newType = RecogniseCommonTypes(type);
- if(newType != null)
- {
- if(!applyDefaultBehaviour) {
- throw new ArgumentException(
- "Default behaviour must be observed for certain types with special handling; " + type.FullName,
- "applyDefaultBehaviour");
- }
- // we should assume that type is fully configured, though; no need to re-run:
- applyDefaultBehaviour = false;
- }
- if(newType == null) newType = Create(type);
- newType.Pending = true;
- TakeLock(ref opaqueToken);
- // double checked
- if (FindWithoutAdd(type) != null) throw new ArgumentException("Duplicate type", "type");
- ThrowIfFrozen();
- types.Add(newType);
- if (applyDefaultBehaviour) { newType.ApplyDefaultBehaviour(); }
- newType.Pending = false;
- }
- finally
- {
- ReleaseLock(opaqueToken);
- }
-
- return newType;
- }
- #if FEAT_COMPILER && !FX11
- /// <summary>
- /// Should serializers be compiled on demand? It may be useful
- /// to disable this for debugging purposes.
- /// </summary>
- public bool AutoCompile
- {
- get { return GetOption(OPTIONS_AutoCompile); }
- set { SetOption(OPTIONS_AutoCompile, value); }
- }
- #endif
- /// <summary>
- /// Should support for unexpected types be added automatically?
- /// If false, an exception is thrown when unexpected types
- /// are encountered.
- /// </summary>
- public bool AutoAddMissingTypes
- {
- get { return GetOption(OPTIONS_AutoAddMissingTypes); }
- set {
- if (!value && GetOption(OPTIONS_IsDefaultModel))
- {
- throw new InvalidOperationException("The default model must allow missing types");
- }
- ThrowIfFrozen();
- SetOption(OPTIONS_AutoAddMissingTypes, value);
- }
- }
- /// <summary>
- /// Verifies that the model is still open to changes; if not, an exception is thrown
- /// </summary>
- private void ThrowIfFrozen()
- {
- if (GetOption(OPTIONS_Frozen)) throw new InvalidOperationException("The model cannot be changed once frozen");
- }
- /// <summary>
- /// Prevents further changes to this model
- /// </summary>
- public void Freeze()
- {
- if (GetOption(OPTIONS_IsDefaultModel)) throw new InvalidOperationException("The default model cannot be frozen");
- SetOption(OPTIONS_Frozen, true);
- }
- private readonly BasicList types = new BasicList();
- /// <summary>
- /// Provides the key that represents a given type in the current model.
- /// </summary>
- protected override int GetKeyImpl(Type type)
- {
- return GetKey(type, false, true);
- }
- internal int GetKey(Type type, bool demand, bool getBaseKey)
- {
- Helpers.DebugAssert(type != null);
- try
- {
- int typeIndex = FindOrAddAuto(type, demand, true, false);
- if (typeIndex >= 0)
- {
- MetaType mt = (MetaType)types[typeIndex];
- if (getBaseKey)
- {
- mt = MetaType.GetRootType(mt);
- typeIndex = FindOrAddAuto(mt.Type, true, true, false);
- }
- }
- return typeIndex;
- }
- catch (NotSupportedException)
- {
- throw; // re-surface "as-is"
- }
- catch (Exception ex)
- {
- if (ex.Message.IndexOf(type.FullName) >= 0) throw; // already enough info
- throw new ProtoException(ex.Message + " (" + type.FullName + ")", ex);
- }
- }
- /// <summary>
- /// Writes a protocol-buffer representation of the given instance to the supplied stream.
- /// </summary>
- /// <param name="key">Represents the type (including inheritance) to consider.</param>
- /// <param name="value">The existing instance to be serialized (cannot be null).</param>
- /// <param name="dest">The destination stream to write to.</param>
- protected internal override void Serialize(int key, object value, ProtoWriter dest)
- {
- #if FEAT_IKVM
- throw new NotSupportedException();
- #else
- //Helpers.DebugWriteLine("Serialize", value);
- ((MetaType)types[key]).Serializer.Write(value, dest);
- #endif
- }
- /// <summary>
- /// Applies a protocol-buffer stream to an existing instance (which may be null).
- /// </summary>
- /// <param name="key">Represents the type (including inheritance) to consider.</param>
- /// <param name="value">The existing instance to be modified (can be null).</param>
- /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
- /// <returns>The updated instance; this may be different to the instance argument if
- /// either the original instance was null, or the stream defines a known sub-type of the
- /// original instance.</returns>
- protected internal override object Deserialize(int key, object value, ProtoReader source)
- {
- #if FEAT_IKVM
- throw new NotSupportedException();
- #else
- //Helpers.DebugWriteLine("Deserialize", value);
- IProtoSerializer ser = ((MetaType)types[key]).Serializer;
- if (value == null && Helpers.IsValueType(ser.ExpectedType)) {
- if(ser.RequiresOldValue) value = Activator.CreateInstance(ser.ExpectedType);
- return ser.Read(value, source);
- } else {
- return ser.Read(value, source);
- }
- #endif
- }
- #if FEAT_COMPILER
- // this is used by some unit-tests; do not remove
- internal Compiler.ProtoSerializer GetSerializer(IProtoSerializer serializer, bool compiled)
- {
- #if FEAT_IKVM
- throw new NotSupportedException();
- #else
- if (serializer == null) throw new ArgumentNullException("serializer");
- #if FEAT_COMPILER && !FX11
- if (compiled) return Compiler.CompilerContext.BuildSerializer(serializer, this);
- #endif
- return new Compiler.ProtoSerializer(serializer.Write);
- #endif
- }
- #if !FX11
- /// <summary>
- /// Compiles the serializers individually; this is *not* a full
- /// standalone compile, but can significantly boost performance
- /// while allowing additional types to be added.
- /// </summary>
- /// <remarks>An in-place compile can access non-public types / members</remarks>
- public void CompileInPlace()
- {
- foreach (MetaType type in types)
- {
- type.CompileInPlace();
- }
- }
- #endif
- #endif
- //internal override IProtoSerializer GetTypeSerializer(Type type)
- //{ // this list is thread-safe for reading
- // .Serializer;
- //}
- //internal override IProtoSerializer GetTypeSerializer(int key)
- //{ // this list is thread-safe for reading
- // MetaType type = (MetaType)types.TryGet(key);
- // if (type != null) return type.Serializer;
- // throw new KeyNotFoundException();
- //}
-
- #if FEAT_COMPILER
- private void BuildAllSerializers()
- {
- // note that types.Count may increase during this operation, as some serializers
- // bring other types into play
- for (int i = 0; i < types.Count; i++)
- {
- // the primary purpose of this is to force the creation of the Serializer
- MetaType mt = (MetaType)types[i];
- if (mt.Serializer == null)
- throw new InvalidOperationException("No serializer available for " + mt.Type.Name);
- }
- }
- #if !SILVERLIGHT
- internal sealed class SerializerPair : IComparable
- {
- int IComparable.CompareTo(object obj)
- {
- if (obj == null) throw new ArgumentException("obj");
- SerializerPair other = (SerializerPair)obj;
- // we want to bunch all the items with the same base-type together, but we need the items with a
- // different base **first**.
- if (this.BaseKey == this.MetaKey)
- {
- if (other.BaseKey == other.MetaKey)
- { // neither is a subclass
- return this.MetaKey.CompareTo(other.MetaKey);
- }
- else
- { // "other" (only) is involved in inheritance; "other" should be first
- return 1;
- }
- }
- else
- {
- if (other.BaseKey == other.MetaKey)
- { // "this" (only) is involved in inheritance; "this" should be first
- return -1;
- }
- else
- { // both are involved in inheritance
- int result = this.BaseKey.CompareTo(other.BaseKey);
- if (result == 0) result = this.MetaKey.CompareTo(other.MetaKey);
- return result;
- }
- }
- }
- public readonly int MetaKey, BaseKey;
- public readonly MetaType Type;
- public readonly MethodBuilder Serialize, Deserialize;
- public readonly ILGenerator SerializeBody, DeserializeBody;
- public SerializerPair(int metaKey, int baseKey, MetaType type, MethodBuilder serialize, MethodBuilder deserialize,
- ILGenerator serializeBody, ILGenerator deserializeBody)
- {
- this.MetaKey = metaKey;
- this.BaseKey = baseKey;
- this.Serialize = serialize;
- this.Deserialize = deserialize;
- this.SerializeBody = serializeBody;
- this.DeserializeBody = deserializeBody;
- this.Type = type;
- }
- }
- /// <summary>
- /// Fully compiles the current model into a static-compiled model instance
- /// </summary>
- /// <remarks>A full compilation is restricted to accessing public types / members</remarks>
- /// <returns>An instance of the newly created compiled type-model</returns>
- public TypeModel Compile()
- {
- CompilerOptions options = new CompilerOptions();
- return Compile(options);
- }
- static ILGenerator Override(TypeBuilder type, string name)
- {
- MethodInfo baseMethod = type.BaseType.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance);
- ParameterInfo[] parameters = baseMethod.GetParameters();
- Type[] paramTypes = new Type[parameters.Length];
- for(int i = 0 ; i < paramTypes.Length ; i++) {
- paramTypes[i] = parameters[i].ParameterType;
- }
- MethodBuilder newMethod = type.DefineMethod(baseMethod.Name,
- (baseMethod.Attributes & ~MethodAttributes.Abstract) | MethodAttributes.Final, baseMethod.CallingConvention, baseMethod.ReturnType, paramTypes);
- ILGenerator il = newMethod.GetILGenerator();
- type.DefineMethodOverride(newMethod, baseMethod);
- return il;
- }
- #if FEAT_IKVM
- /// <summary>
- /// Inspect the model, and resolve all related types
- /// </summary>
- public void Cascade()
- {
- BuildAllSerializers();
- }
- /// <summary>
- /// Translate a System.Type into the universe's type representation
- /// </summary>
- protected internal override Type MapType(System.Type type, bool demand)
- {
- if (type == null) return null;
- #if DEBUG
- if (type.Assembly == typeof(IKVM.Reflection.Type).Assembly)
- {
- throw new InvalidOperationException(string.Format(
- "Somebody is passing me IKVM types! {0} should be fully-qualified at the call-site",
- type.Name));
- }
- #endif
- Type result = universe.GetType(type.AssemblyQualifiedName);
-
- if(result == null)
- {
- // things also tend to move around... *a lot* - especially in WinRT; search all as a fallback strategy
- foreach (Assembly a in universe.GetAssemblies())
- {
- result = a.GetType(type.FullName);
- if (result != null) break;
- }
- if (result == null && demand)
- {
- throw new InvalidOperationException("Unable to map type: " + type.AssemblyQualifiedName);
- }
- }
- return result;
- }
- #endif
- /// <summary>
- /// Represents configuration options for compiling a model to
- /// a standalone assembly.
- /// </summary>
- public sealed class CompilerOptions
- {
- /// <summary>
- /// Import framework options from an existing type
- /// </summary>
- public void SetFrameworkOptions(MetaType from)
- {
- if (from == null) throw new ArgumentNullException("from");
- AttributeMap[] attribs = AttributeMap.Create(from.Model, Helpers.GetAssembly(from.Type));
- foreach (AttributeMap attrib in attribs)
- {
- if (attrib.AttributeType.FullName == "System.Runtime.Versioning.TargetFrameworkAttribute")
- {
- object tmp;
- if (attrib.TryGet("FrameworkName", out tmp)) TargetFrameworkName = (string)tmp;
- if (attrib.TryGet("FrameworkDisplayName", out tmp)) TargetFrameworkDisplayName = (string)tmp;
- break;
- }
- }
- }
- private string targetFrameworkName, targetFrameworkDisplayName, typeName, outputPath, imageRuntimeVersion;
- private int metaDataVersion;
- /// <summary>
- /// The TargetFrameworkAttribute FrameworkName value to burn into the generated assembly
- /// </summary>
- public string TargetFrameworkName { get { return targetFrameworkName; } set { targetFrameworkName = value; } }
- /// <summary>
- /// The TargetFrameworkAttribute FrameworkDisplayName value to burn into the generated assembly
- /// </summary>
- public string TargetFrameworkDisplayName { get { return targetFrameworkDisplayName; } set { targetFrameworkDisplayName = value; } }
- /// <summary>
- /// The name of the TypeModel class to create
- /// </summary>
- public string TypeName { get { return typeName; } set { typeName = value; } }
- #if COREFX
- internal const string NoPersistence = "Assembly persistence not supported on this runtime";
- #endif
- /// <summary>
- /// The path for the new dll
- /// </summary>
- #if COREFX
- [Obsolete(NoPersistence)]
- #endif
- public string OutputPath { get { return outputPath; } set { outputPath = value; } }
- /// <summary>
- /// The runtime version for the generated assembly
- /// </summary>
- public string ImageRuntimeVersion { get { return imageRuntimeVersion; } set { imageRuntimeVersion = value; } }
- /// <summary>
- /// The runtime version for the generated assembly
- /// </summary>
- public int MetaDataVersion { get { return metaDataVersion; } set { metaDataVersion = value; } }
- private Accessibility accessibility = Accessibility.Public;
- /// <summary>
- /// The acecssibility of the generated serializer
- /// </summary>
- public Accessibility Accessibility { get { return accessibility; } set { accessibility = value; } }
- #if FEAT_IKVM
- /// <summary>
- /// The name of the container that holds the key pair.
- /// </summary>
- public string KeyContainer { get; set; }
- /// <summary>
- /// The path to a file that hold the key pair.
- /// </summary>
- public string KeyFile { get; set; }
- /// <summary>
- /// The public key to sign the file with.
- /// </summary>
- public string PublicKey { get; set; }
- #endif
- }
- /// <summary>
- /// Type accessibility
- /// </summary>
- public enum Accessibility
- {
- /// <summary>
- /// Available to all callers
- /// </summary>
- Public,
- /// <summary>
- /// Available to all callers in the same assembly, or assemblies specified via [InternalsVisibleTo(...)]
- /// </summary>
- Internal
- }
- #if !COREFX
- /// <summary>
- /// Fully compiles the current model into a static-compiled serialization dll
- /// (the serialization dll still requires protobuf-net for support services).
- /// </summary>
- /// <remarks>A full compilation is restricted to accessing public types / members</remarks>
- /// <param name="name">The name of the TypeModel class to create</param>
- /// <param name="path">The path for the new dll</param>
- /// <returns>An instance of the newly created compiled type-model</returns>
- public TypeModel Compile(string name, string path)
- {
- CompilerOptions options = new CompilerOptions();
- options.TypeName = name;
- options.OutputPath = path;
- return Compile(options);
- }
- #endif
- /// <summary>
- /// Fully compiles the current model into a static-compiled serialization dll
- /// (the serialization dll still requires protobuf-net for support services).
- /// </summary>
- /// <remarks>A full compilation is restricted to accessing public types / members</remarks>
- /// <returns>An instance of the newly created compiled type-model</returns>
- public TypeModel Compile(CompilerOptions options)
- {
- if (options == null) throw new ArgumentNullException("options");
- string typeName = options.TypeName;
- #pragma warning disable 0618
- string path = options.OutputPath;
- #pragma warning restore 0618
- BuildAllSerializers();
- Freeze();
- bool save = !Helpers.IsNullOrEmpty(path);
- if (Helpers.IsNullOrEmpty(typeName))
- {
- if (save) throw new ArgumentNullException("typeName");
- typeName = Guid.NewGuid().ToString();
- }
- string assemblyName, moduleName;
- if(path == null)
- {
- assemblyName = typeName;
- moduleName = assemblyName + ".dll";
- }
- else
- {
- assemblyName = new System.IO.FileInfo(System.IO.Path.GetFileNameWithoutExtension(path)).Name;
- moduleName = assemblyName + System.IO.Path.GetExtension(path);
- }
- #if FEAT_IKVM
- IKVM.Reflection.AssemblyName an = new IKVM.Reflection.AssemblyName();
- an.Name = assemblyName;
- AssemblyBuilder asm = universe.DefineDynamicAssembly(an, AssemblyBuilderAccess.Save);
- if (!Helpers.IsNullOrEmpty(options.KeyFile))
- {
- asm.__SetAssemblyKeyPair(new StrongNameKeyPair(File.OpenRead(options.KeyFile)));
- }
- else if (!Helpers.IsNullOrEmpty(options.KeyContainer))
- {
- asm.__SetAssemblyKeyPair(new StrongNameKeyPair(options.KeyContainer));
- }
- else if (!Helpers.IsNullOrEmpty(options.PublicKey))
- {
- asm.__SetAssemblyPublicKey(FromHex(options.PublicKey));
- }
- if(!Helpers.IsNullOrEmpty(options.ImageRuntimeVersion) && options.MetaDataVersion != 0)
- {
- asm.__SetImageRuntimeVersion(options.ImageRuntimeVersion, options.MetaDataVersion);
- }
- ModuleBuilder module = asm.DefineDynamicModule(moduleName, path);
- #elif COREFX
- AssemblyName an = new AssemblyName();
- an.Name = assemblyName;
- AssemblyBuilder asm = AssemblyBuilder.DefineDynamicAssembly(an,
- AssemblyBuilderAccess.Run);
- ModuleBuilder module = asm.DefineDynamicModule(moduleName);
- #else
- AssemblyName an = new AssemblyName();
- an.Name = assemblyName;
- AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(an,
- (save ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run)
- );
- ModuleBuilder module = save ? asm.DefineDynamicModule(moduleName, path)
- : asm.DefineDynamicModule(moduleName);
- #endif
- WriteAssemblyAttributes(options, assemblyName, asm);
- TypeBuilder type = WriteBasicTypeModel(options, typeName, module);
- int index;
- bool hasInheritance;
- SerializerPair[] methodPairs;
- Compiler.CompilerContext.ILVersion ilVersion;
- WriteSerializers(options, assemblyName, type, out index, out hasInheritance, out methodPairs, out ilVersion);
- ILGenerator il;
- int knownTypesCategory;
- FieldBuilder knownTypes;
- Type knownTypesLookupType;
- WriteGetKeyImpl(type, hasInheritance, methodPairs, ilVersion, assemblyName, out il, out knownTypesCategory, out knownTypes, out knownTypesLookupType);
- // trivial flags
- il = Override(type, "SerializeDateTimeKind");
- il.Emit(IncludeDateTimeKind ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
- il.Emit(OpCodes.Ret);
- // end: trivial flags
- Compiler.CompilerContext ctx = WriteSerializeDeserialize(assemblyName, type, methodPairs, ilVersion, ref il);
- WriteConstructors(type, ref index, methodPairs, ref il, knownTypesCategory, knownTypes, knownTypesLookupType, ctx);
- #if COREFX
- Type finalType = type.CreateTypeInfo().AsType();
- #else
- Type finalType = type.CreateType();
- #endif
- if (!Helpers.IsNullOrEmpty(path))
- {
- #if COREFX
- throw new NotSupportedException(CompilerOptions.NoPersistence);
- #else
- asm.Save(path);
- Helpers.DebugWriteLine("Wrote dll:" + path);
- #endif
- }
- #if FEAT_IKVM
- return null;
- #else
- return (TypeModel)Activator.CreateInstance(finalType);
- #endif
- }
- #if FEAT_IKVM
- private byte[] FromHex(string value)
- {
- if (Helpers.IsNullOrEmpty(value)) throw new ArgumentNullException("value");
- int len = value.Length / 2;
- byte[] result = new byte[len];
- for(int i = 0 ; i < len ; i++)
- {
- result[i] = Convert.ToByte(value.Substring(i * 2, 2), 16);
- }
- return result;
- }
- #endif
- private void WriteConstructors(TypeBuilder type, ref int index, SerializerPair[] methodPairs, ref ILGenerator il, int knownTypesCategory, FieldBuilder knownTypes, Type knownTypesLookupType, Compiler.CompilerContext ctx)
- {
- type.DefineDefaultConstructor(MethodAttributes.Public);
- il = type.DefineTypeInitializer().GetILGenerator();
- switch (knownTypesCategory)
- {
- case KnownTypes_Array:
- {
- Compiler.CompilerContext.LoadValue(il, types.Count);
- il.Emit(OpCodes.Newarr, ctx.MapType(typeof(System.Type)));
- index = 0;
- foreach (SerializerPair pair in methodPairs)
- {
- il.Emit(OpCodes.Dup);
- Compiler.CompilerContext.LoadValue(il, index);
- il.Emit(OpCodes.Ldtoken, pair.Type.Type);
- il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null);
- il.Emit(OpCodes.Stelem_Ref);
- index++;
- }
- il.Emit(OpCodes.Stsfld, knownTypes);
- il.Emit(OpCodes.Ret);
- }
- break;
- case KnownTypes_Dictionary:
- {
- Compiler.CompilerContext.LoadValue(il, types.Count);
- //LocalBuilder loc = il.DeclareLocal(knownTypesLookupType);
- il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) }));
- il.Emit(OpCodes.Stsfld, knownTypes);
- int typeIndex = 0;
- foreach (SerializerPair pair in methodPairs)
- {
- il.Emit(OpCodes.Ldsfld, knownTypes);
- il.Emit(OpCodes.Ldtoken, pair.Type.Type);
- il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null);
- int keyIndex = typeIndex++, lastKey = pair.BaseKey;
- if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type
- {
- keyIndex = -1; // assume epic fail
- for (int j = 0; j < methodPairs.Length; j++)
- {
- if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey)
- {
- keyIndex = j;
- break;
- }
- }
- }
- Compiler.CompilerContext.LoadValue(il, keyIndex);
- il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(System.Type)), MapType(typeof(int)) }), null);
- }
- il.Emit(OpCodes.Ret);
- }
- break;
- case KnownTypes_Hashtable:
- {
- Compiler.CompilerContext.LoadValue(il, types.Count);
- il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) }));
- il.Emit(OpCodes.Stsfld, knownTypes);
- int typeIndex = 0;
- foreach (SerializerPair pair in methodPairs)
- {
- il.Emit(OpCodes.Ldsfld, knownTypes);
- il.Emit(OpCodes.Ldtoken, pair.Type.Type);
- il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null);
- int keyIndex = typeIndex++, lastKey = pair.BaseKey;
- if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type
- {
- keyIndex = -1; // assume epic fail
- for (int j = 0; j < methodPairs.Length; j++)
- {
- if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey)
- {
- keyIndex = j;
- break;
- }
- }
- }
- Compiler.CompilerContext.LoadValue(il, keyIndex);
- il.Emit(OpCodes.Box, MapType(typeof(int)));
- il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(object)), MapType(typeof(object)) }), null);
- }
- il.Emit(OpCodes.Ret);
- }
- break;
- default:
- throw new InvalidOperationException();
- }
- }
- private Compiler.CompilerContext WriteSerializeDeserialize(string assemblyName, TypeBuilder type, SerializerPair[] methodPairs, Compiler.CompilerContext.ILVersion ilVersion, ref ILGenerator il)
- {
- il = Override(type, "Serialize");
- Compiler.CompilerContext ctx = new Compiler.CompilerContext(il, false, true, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object)), "Serialize " + type.Name);
- // arg0 = this, arg1 = key, arg2=obj, arg3=dest
- Compiler.CodeLabel[] jumpTable = new Compiler.CodeLabel[types.Count];
- for (int i = 0; i < jumpTable.Length; i++)
- {
- jumpTable[i] = ctx.DefineLabel();
- }
- il.Emit(OpCodes.Ldarg_1);
- ctx.Switch(jumpTable);
- ctx.Return();
- for (int i = 0; i < jumpTable.Length; i++)
- {
- SerializerPair pair = methodPairs[i];
- ctx.MarkLabel(jumpTable[i]);
- il.Emit(OpCodes.Ldarg_2);
- ctx.CastFromObject(pair.Type.Type);
- il.Emit(OpCodes.Ldarg_3);
- il.EmitCall(OpCodes.Call, pair.Serialize, null);
- ctx.Return();
- }
- il = Override(type, "Deserialize");
- ctx = new Compiler.CompilerContext(il, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object)), "Deserialize " + type.Name);
- // arg0 = this, arg1 = key, arg2=obj, arg3=source
- for (int i = 0; i < jumpTable.Length; i++)
- {
- jumpTable[i] = ctx.DefineLabel();
- }
- il.Emit(OpCodes.Ldarg_1);
- ctx.Switch(jumpTable);
- ctx.LoadNullRef();
- ctx.Return();
- for (int i = 0; i < jumpTable.Length; i++)
- {
- SerializerPair pair = methodPairs[i];
- ctx.MarkLabel(jumpTable[i]);
- Type keyType = pair.Type.Type;
- if (Helpers.IsValueType(keyType))
- {
- il.Emit(OpCodes.Ldarg_2);
- il.Emit(OpCodes.Ldarg_3);
- il.EmitCall(OpCodes.Call, EmitBoxedSerializer(type, i, keyType, methodPairs, this, ilVersion, assemblyName), null);
- ctx.Return();
- }
- else
- {
- il.Emit(OpCodes.Ldarg_2);
- ctx.CastFromObject(keyType);
- il.Emit(OpCodes.Ldarg_3);
- il.EmitCall(OpCodes.Call, pair.Deserialize, null);
- ctx.Return();
- }
- }
- return ctx;
- }
- private const int KnownTypes_Array = 1, KnownTypes_Dictionary = 2, KnownTypes_Hashtable = 3, KnownTypes_ArrayCutoff = 20;
- 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)
- {
- il = Override(type, "GetKeyImpl");
- Compiler.CompilerContext ctx = new Compiler.CompilerContext(il, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(System.Type), true), "GetKeyImpl");
- 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 !COREFX
- if (knownTypesLookupType == null)
- {
- knownTypesLookupType = MapType(typeof(Hashtable), true);
- knownTypesCategory = KnownTypes_Hashtable;
- }
- else
- #endif
- {
- 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();
- }
- }
- private void WriteSerializers(CompilerOptions options, string assemblyName, TypeBuilder type, out int index, out bool hasInheritance, out SerializerPair[] methodPairs, out Compiler.CompilerContext.ILVersion ilVersion)
- {
- Compiler.CompilerContext ctx;
- index = 0;
- hasInheritance = false;
- methodPairs = new SerializerPair[types.Count];
- foreach (MetaType metaType in types)
- {
- MethodBuilder writeMethod = type.DefineMethod("Write"
- #if DEBUG
- + metaType.Type.Name
- #endif
- ,
- MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard,
- MapType(typeof(void)), new Type[] { metaType.Type, MapType(typeof(ProtoWriter)) });
- MethodBuilder readMethod = type.DefineMethod("Read"
- #if DEBUG
- + metaType.Type.Name
- #endif
- ,
- MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard,
- metaType.Type, new Type[] { metaType.Type, MapType(typeof(ProtoReader)) });
- SerializerPair pair = new SerializerPair(
- GetKey(metaType.Type, true, false), GetKey(metaType.Type, true, true), metaType,
- writeMethod, readMethod, writeMethod.GetILGenerator(), readMethod.GetILGenerator());
- methodPairs[index++] = pair;
- if (pair.MetaKey != pair.BaseKey) hasInheritance = true;
- }
- if (hasInheritance)
- {
- Array.Sort(methodPairs);
- }
- ilVersion = Compiler.CompilerContext.ILVersion.Net2;
- if (options.MetaDataVersion == 0x10000)
- {
- ilVersion = Compiler.CompilerContext.ILVersion.Net1; // old-school!
- }
- for (index = 0; index < methodPairs.Length; index++)
- {
- SerializerPair pair = methodPairs[index];
- ctx = new Compiler.CompilerContext(pair.SerializeBody, true, true, methodPairs, this, ilVersion, assemblyName, pair.Type.Type, "SerializeImpl " + pair.Type.Type.Name);
- ctx.CheckAccessibility(pair.Deserialize.ReturnType
- #if COREFX
- .GetTypeInfo()
- #endif
- );
- pair.Type.Serializer.EmitWrite(ctx, ctx.InputValue);
- ctx.Return();
- ctx = new Compiler.CompilerContext(pair.DeserializeBody, true, false, methodPairs, this, ilVersion, assemblyName, pair.Type.Type, "DeserializeImpl " + pair.Type.Type.Name);
- pair.Type.Serializer.EmitRead(ctx, ctx.InputValue);
- if (!pair.Type.Serializer.ReturnsValue)
- {
- ctx.LoadValue(ctx.InputValue);
- }
- ctx.Return();
- }
- }
- private TypeBuilder WriteBasicTypeModel(CompilerOptions options, string typeName, ModuleBuilder module)
- {
- Type baseType = MapType(typeof(TypeModel));
- #if COREFX
- TypeAttributes typeAttributes = (baseType.GetTypeInfo().Attributes & ~TypeAttributes.Abstract) | TypeAttributes.Sealed;
- #else
- TypeAttributes typeAttributes = (baseType.Attributes & ~TypeAttributes.Abstract) | TypeAttributes.Sealed;
- #endif
- if (options.Accessibility == Accessibility.Internal)
- {
- typeAttributes &= ~TypeAttributes.Public;
- }
- TypeBuilder type = module.DefineType(typeName, typeAttributes, baseType);
- return type;
- }
- private void WriteAssemblyAttributes(CompilerOptions options, string assemblyName, AssemblyBuilder asm)
- {
- if (!Helpers.IsNullOrEmpty(options.TargetFrameworkName))
- {
- // get [TargetFramework] from mscorlib/equivalent and burn into the new assembly
- Type versionAttribType = null;
- try
- { // this is best-endeavours only
- versionAttribType = GetType("System.Runtime.Versioning.TargetFrameworkAttribute", Helpers.GetAssembly(MapType(typeof(string))));
- }
- catch { /* don't stress */ }
- if (versionAttribType != null)
- {
- PropertyInfo[] props;
- object[] propValues;
- if (Helpers.IsNullOrEmpty(options.TargetFrameworkDisplayName))
- {
- props = new PropertyInfo[0];
- propValues = new object[0];
- }
- else
- {
- props = new PropertyInfo[1] { versionAttribType.GetProperty("FrameworkDisplayName") };
- propValues = new object[1] { options.TargetFrameworkDisplayName };
- }
- CustomAttributeBuilder builder = new CustomAttributeBuilder(
- versionAttribType.GetConstructor(new Type[] { MapType(typeof(string)) }),
- new object[] { options.TargetFrameworkName },
- props,
- propValues);
- asm.SetCustomAttribute(builder);
- }
- }
- // copy assembly:InternalsVisibleTo
- Type internalsVisibleToAttribType = null;
- #if !FX11
- try
- {
- internalsVisibleToAttribType = MapType(typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute));
- }
- catch { /* best endeavors only */ }
- #endif
- if (internalsVisibleToAttribType != null)
- {
- BasicList internalAssemblies = new BasicList(), consideredAssemblies = new BasicList();
- foreach (MetaType metaType in types)
- {
- Assembly assembly = Helpers.GetAssembly(metaType.Type);
- if (consideredAssemblies.IndexOfReference(assembly) >= 0) continue;
- consideredAssemblies.Add(assembly);
- AttributeMap[] assemblyAttribsMap = AttributeMap.Create(this, assembly);
- for (int i = 0; i < assemblyAttribsMap.Length; i++)
- {
- if (assemblyAttribsMap[i].AttributeType != internalsVisibleToAttribType) continue;
- object privelegedAssemblyObj;
- assemblyAttribsMap[i].TryGet("AssemblyName", out privelegedAssemblyObj);
- string privelegedAssemblyName = privelegedAssemblyObj as string;
- if (privelegedAssemblyName == assemblyName || Helpers.IsNullOrEmpty(privelegedAssemblyName)) continue; // ignore
- if (internalAssemblies.IndexOfString(privelegedAssemblyName) >= 0) continue; // seen it before
- internalAssemblies.Add(privelegedAssemblyName);
- CustomAttributeBuilder builder = new CustomAttributeBuilder(
- internalsVisibleToAttribType.GetConstructor(new Type[] { MapType(typeof(string)) }),
- new object[] { privelegedAssemblyName });
- asm.SetCustomAttribute(builder);
- }
- }
- }
- }
- private static MethodBuilder EmitBoxedSerializer(TypeBuilder type, int i, Type valueType, SerializerPair[] methodPairs, TypeModel model, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName)
- {
- MethodInfo dedicated = methodPairs[i].Deserialize;
- MethodBuilder boxedSerializer = type.DefineMethod("_" + i.ToString(), MethodAttributes.Static, CallingConventions.Standard,
- model.MapType(typeof(object)), new Type[] { model.MapType(typeof(object)), model.MapType(typeof(ProtoReader)) });
- Compiler.CompilerContext ctx = new Compiler.CompilerContext(boxedSerializer.GetILGenerator(), true, false, methodPairs, model, ilVersion, assemblyName, model.MapType(typeof(object)), "BoxedSerializer " + valueType.Name);
- ctx.LoadValue(ctx.InputValue);
- Compiler.CodeLabel @null = ctx.DefineLabel();
- ctx.BranchIfFalse(@null, true);
- Type mappedValueType = valueType;
- ctx.LoadValue(ctx.InputValue);
- ctx.CastFromObject(mappedValueType);
- ctx.LoadReaderWriter();
- ctx.EmitCall(dedicated);
- ctx.CastToObject(mappedValueType);
- ctx.Return();
- ctx.MarkLabel(@null);
- using (Compiler.Local typedVal = new Compiler.Local(ctx, mappedValueType))
- {
- // create a new valueType
- ctx.LoadAddress(typedVal, mappedValueType);
- ctx.EmitCtor(mappedValueType);
- ctx.LoadValue(typedVal);
- ctx.LoadReaderWriter();
- ctx.EmitCall(dedicated);
- ctx.CastToObject(mappedValueType);
- ctx.Return();
- }
- return boxedSerializer;
- }
-
- #endif
- #endif
- //internal bool IsDefined(Type type, int fieldNumber)
- //{
- // return FindWithoutAdd(type).IsDefined(fieldNumber);
- //}
- // note that this is used by some of the unit tests
- internal bool IsPrepared(Type type)
- {
- MetaType meta = FindWithoutAdd(type);
- return meta != null && meta.IsPrepared();
- }
- internal EnumSerializer.EnumPair[] GetEnumMap(Type type)
- {
- int index = FindOrAddAuto(type, false, false, false);
- return index < 0 ? null : ((MetaType)types[index]).GetEnumMap();
- }
- private int metadataTimeoutMilliseconds = 5000;
- /// <summary>
- /// The amount of time to wait if there are concurrent metadata access operations
- /// </summary>
- public int MetadataTimeoutMilliseconds
- {
- get { return metadataTimeoutMilliseconds; }
- set
- {
- if (value <= 0) throw new ArgumentOutOfRangeException("MetadataTimeoutMilliseconds");
- metadataTimeoutMilliseconds = value;
- }
- }
- #if DEBUG
- int lockCount;
- /// <summary>
- /// Gets how many times a model lock was taken
- /// </summary>
- public int LockCount { get { return lockCount; } }
- #endif
- internal void TakeLock(ref int opaqueToken)
- {
- const string message = "Timeout while inspecting metadata; this may indicate a deadlock. This can often be avoided by preparing necessary serializers during application initialization, rather than allowing multiple threads to perform the initial metadata inspection; please also see the LockContended event";
- opaqueToken = 0;
- #if PORTABLE
- if(!Monitor.TryEnter(types, metadataTimeoutMilliseconds)) throw new TimeoutException(message);
- opaqueToken = Interlocked.CompareExchange(ref contentionCounter, 0, 0); // just fetch current value (starts at 1)
- #elif CF2 || CF35
- int remaining = metadataTimeoutMilliseconds;
- bool lockTaken;
- do {
- lockTaken = Monitor.TryEnter(types);
- if(!lockTaken)
- {
- if(remaining <= 0) throw new TimeoutException(message);
- remaining -= 50;
- Thread.Sleep(50);
- }
- } while(!lockTaken);
- opaqueToken = Interlocked.CompareExchange(ref contentionCounter, 0, 0); // just fetch current value (starts at 1)
- #else
- if (Monitor.TryEnter(types, metadataTimeoutMilliseconds))
- {
- opaqueToken = GetContention(); // just fetch current value (starts at 1)
- }
- else
- {
- AddContention();
- #if FX11
- throw new InvalidOperationException(message);
- #else
- throw new TimeoutException(message);
- #endif
- }
- #endif
- #if DEBUG // note that here, through all code-paths: we have the lock
- lockCount++;
- #endif
- }
- private int contentionCounter = 1;
- #if PLAT_NO_INTERLOCKED
- private readonly object contentionLock = new object();
- #endif
- private int GetContention()
- {
- #if PLAT_NO_INTERLOCKED
- lock(contentionLock)
- {
- return contentionCounter;
- }
- #else
- return Interlocked.CompareExchange(ref contentionCounter, 0, 0);
- #endif
- }
- private void AddContention()
- {
- #if PLAT_NO_INTERLOCKED
- lock(contentionLock)
- {
- contentionCounter++;
- }
- #else
- Interlocked.Increment(ref contentionCounter);
- #endif
- }
- internal void ReleaseLock(int opaqueToken)
- {
- if (opaqueToken != 0)
- {
- Monitor.Exit(types);
- if(opaqueToken != GetContention()) // contention-count changes since we looked!
- {
- LockContentedEventHandler handler = LockContended;
- if (handler != null)
- {
- // not hugely elegant, but this is such a far-corner-case that it doesn't need to be slick - I'll settle for cross-platform
- string stackTrace;
- try
- {
- throw new ProtoException();
- }
- catch(Exception ex)
- {
- stackTrace = ex.StackTrace;
- }
-
- handler(this, new LockContentedEventArgs(stackTrace));
- }
- }
- }
- }
- /// <summary>
- /// If a lock-contention is detected, this event signals the *owner* of the lock responsible for the blockage, indicating
- /// what caused the problem; this is only raised if the lock-owning code successfully completes.
- /// </summary>
- public event LockContentedEventHandler LockContended;
- internal void ResolveListTypes(Type type, ref Type itemType, ref Type defaultType)
- {
- if (type == null) return;
- if(Helpers.GetTypeCode(type) != ProtoTypeCode.Unknown) return; // don't try this[type] for inbuilts
- if(this[type].IgnoreListHandling) return;
- // handle arrays
- if (type.IsArray)
- {
- if (type.GetArrayRank() != 1)
- {
- throw new NotSupportedException("Multi-dimension arrays are supported");
- }
- itemType = type.GetElementType();
- if (itemType == MapType(typeof(byte)))
- {
- defaultType = itemType = null;
- }
- else
- {
- defaultType = type;
- }
- }
- // handle lists
- if (itemType == null) { itemType = TypeModel.GetListItemType(this, type); }
- // check for nested data (not allowed)
- if (itemType != null)
- {
- Type nestedItemType = null, nestedDefaultType = null;
- ResolveListTypes(itemType, ref nestedItemType, ref nestedDefaultType);
- if (nestedItemType != null)
- {
- throw TypeModel.CreateNestedListsNotSupported();
- }
- }
- if (itemType != null && defaultType == null)
- {
- #if WINRT || COREFX
- System.Reflection.TypeInfo typeInfo = System.Reflection.IntrospectionExtensions.GetTypeInfo(type);
- if (typeInfo.IsClass && !typeInfo.IsAbstract && Helpers.GetConstructor(typeInfo, Helpers.EmptyTypes, true) != null)
- #else
- if (type.IsClass && !type.IsAbstract && Helpers.GetConstructor(type, Helpers.EmptyTypes, true) != null)
- #endif
- {
- defaultType = type;
- }
- if (defaultType == null)
- {
- #if WINRT || COREFX
- if (typeInfo.IsInterface)
- #else
- if (type.IsInterface)
- #endif
- {
- #if NO_GENERICS
- defaultType = typeof(ArrayList);
- #else
- Type[] genArgs;
- #if WINRT || COREFX
- if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>)
- && itemType == typeof(System.Collections.Generic.KeyValuePair<,>).MakeGenericType(genArgs = typeInfo.GenericTypeArguments))
- #else
- if (type.IsGenericType && type.GetGenericTypeDefinition() == MapType(typeof(System.Collections.Generic.IDictionary<,>))
- && itemType == MapType(typeof(System.Collections.Generic.KeyValuePair<,>)).MakeGenericType(genArgs = type.GetGenericArguments()))
- #endif
- {
- defaultType = MapType(typeof(System.Collections.Generic.Dictionary<,>)).MakeGenericType(genArgs);
- }
- else
- {
- defaultType = MapType(typeof(System.Collections.Generic.List<>)).MakeGenericType(itemType);
- }
- #endif
- }
- }
- // verify that the default type is appropriate
- if (defaultType != null && !Helpers.IsAssignableFrom(type, defaultType)) { defaultType = null; }
- }
- }
-
- #if FEAT_IKVM
- internal override Type GetType(string fullName, Assembly context)
- {
- if (context != null)
- {
- Type found = universe.GetType(context, fullName, false);
- if (found != null) return found;
- }
- return universe.GetType(fullName, false);
- }
- #endif
- internal string GetSchemaTypeName(Type effectiveType, DataFormat dataFormat, bool asReference, bool dynamicType, ref bool requiresBclImport)
- {
- Type tmp = Helpers.GetUnderlyingType(effectiveType);
- if (tmp != null) effectiveType = tmp;
- if (effectiveType == this.MapType(typeof(byte[]))) return "bytes";
- WireType wireType;
- IProtoSerializer ser = ValueMember.TryGetCoreSerializer(this, dataFormat, effectiveType, out wireType, false, false, false, false);
- if (ser == null)
- { // model type
- if (asReference || dynamicType)
- {
- requiresBclImport = true;
- return "bcl.NetObjectProxy";
- }
- return this[effectiveType].GetSurrogateOrBaseOrSelf(true).GetSchemaTypeName();
- }
- else
- {
- if (ser is ParseableSerializer)
- {
- if (asReference) requiresBclImport = true;
- return asReference ? "bcl.NetObjectProxy" : "string";
- }
- switch (Helpers.GetTypeCode(effectiveType))
- {
- case ProtoTypeCode.Boolean: return "bool";
- case ProtoTypeCode.Single: return "float";
- case ProtoTypeCode.Double: return "double";
- case ProtoTypeCode.String:
- if (asReference) requiresBclImport = true;
- return asReference ? "bcl.NetObjectProxy" : "string";
- case ProtoTypeCode.Byte:
- case ProtoTypeCode.Char:
- case ProtoTypeCode.UInt16:
- case ProtoTypeCode.UInt32:
- switch (dataFormat)
- {
- case DataFormat.FixedSize: return "fixed32";
- default: return "uint32";
- }
- case ProtoTypeCode.SByte:
- case ProtoTypeCode.Int16:
- case ProtoTypeCode.Int32:
- switch (dataFormat)
- {
- case DataFormat.ZigZag: return "sint32";
- case DataFormat.FixedSize: return "sfixed32";
- default: return "int32";
- }
- case ProtoTypeCode.UInt64:
- switch (dataFormat)
- {
- case DataFormat.FixedSize: return "fixed64";
- default: return "uint64";
- }
- case ProtoTypeCode.Int64:
- switch (dataFormat)
- {
- case DataFormat.ZigZag: return "sint64";
- case DataFormat.FixedSize: return "sfixed64";
- default: return "int64";
- }
- case ProtoTypeCode.DateTime: requiresBclImport = true; return "bcl.DateTime";
- case ProtoTypeCode.TimeSpan: requiresBclImport = true; return "bcl.TimeSpan";
- case ProtoTypeCode.Decimal: requiresBclImport = true; return "bcl.Decimal";
- case ProtoTypeCode.Guid: requiresBclImport = true; return "bcl.Guid";
- default: throw new NotSupportedException("No .proto map found for: " + effectiveType.FullName);
- }
- }
- }
- /// <summary>
- /// Designate a factory-method to use to create instances of any type; note that this only affect types seen by the serializer *after* setting the factory.
- /// </summary>
- public void SetDefaultFactory(MethodInfo methodInfo)
- {
- VerifyFactory(methodInfo, null);
- defaultFactory = methodInfo;
- }
- private MethodInfo defaultFactory;
- internal void VerifyFactory(MethodInfo factory, Type type)
- {
- if (factory != null)
- {
- if (type != null && Helpers.IsValueType(type)) throw new InvalidOperationException();
- if (!factory.IsStatic) throw new ArgumentException("A factory-method must be static", "factory");
- if ((type != null && factory.ReturnType != type) && factory.ReturnType != MapType(typeof(object))) throw new ArgumentException("The factory-method must return object" + (type == null ? "" : (" or " + type.FullName)), "factory");
- if (!CallbackSet.CheckCallbackParameters(this, factory)) throw new ArgumentException("Invalid factory signature in " + factory.DeclaringType.FullName + "." + factory.Name, "factory");
- }
- }
- }
- /// <summary>
- /// Contains the stack-trace of the owning code when a lock-contention scenario is detected
- /// </summary>
- public sealed class LockContentedEventArgs : EventArgs
- {
- private readonly string ownerStackTrace;
- internal LockContentedEventArgs(string ownerStackTrace)
- {
- this.ownerStackTrace = ownerStackTrace;
- }
- /// <summary>
- /// The stack-trace of the code that owned the lock when a lock-contention scenario occurred
- /// </summary>
- public string OwnerStackTrace { get { return ownerStackTrace; } }
- }
- /// <summary>
- /// Event-type that is raised when a lock-contention scenario is detected
- /// </summary>
- public delegate void LockContentedEventHandler(object sender, LockContentedEventArgs args);
- }
- #endif
|