ãã£ãã·ã¥ã®ãªãææ°ã®ãµãŒãã¹ã§ã¯ãã©ãã«ããããŸãããæ°žç¶ããŒã¿ããŒã¹å ã®ããŒã¿ãžã®ã¢ã¯ã»ã¹ã¯é·ããŠè²»çšã®ãããããžãã¹ãªã®ã§ãæãé »ç¹ã«äœ¿çšãããããŒã¿ã«äžéã¹ãã¬ãŒãžãè¿œå ãããšãé床ãå€§å¹ ã«åäžããŸãã æ å ±ã¯ãã©ã€ã³ããªã¹ããã»ãã·ã§ã³ç¶æ ãªã©ãããŸããŸãªæ¹æ³ã§ããŸããŸãªåœ¢åŒã§ãã£ãã·ã¥ã«ä¿æã§ããŸãã ãã®èšäºã§ã¯ããã¹ããããã¯ã©ã¹ãšåŸªç°åç §ãæããªãããã©ããããªããžã§ã¯ãããã£ãã·ã¥ã«ä¿åããæ¹æ³ã®1ã€ã«ã€ããŠèª¬æããŸãã
ãã©ãããªããžã§ã¯ãã®ã«ã¹ã¿ã ã·ãªã¢ã«å
Microsoft Azureã®Redis Cacheãªã©ã®ãã£ãã·ã¥ã¯ãå°ãªããšãStackExchange.Redisã¯ã©ã€ã¢ã³ãã©ã€ãã©ãªã®äžéšãšããŠãçµã¿èŸŒã¿ã®ãªããžã§ã¯ãã·ãªã¢ã«åãæäŸããŸããã ãã£ãã·ã¥ã¯ãç¹å®ã®ããŒã®äžã«ä»»æã®ãã€ãã·ãŒã±ã³ã¹ãä¿åã§ããã¡ãœãããæäŸããŸãããŠãŒã¶ãŒã¯ãä¿åããããªããžã§ã¯ããããã€ããååŸããæ¹æ³ãéžæã§ããŸãã å¯èœãªãªãã·ã§ã³ã®1ã€ã¯æšæºã®.Net BinaryFormatterã§ãããããã ãã§ã¯ãªãããã£ãã·ã¥ã«å€ãã®ãªããžã§ã¯ããæ ŒçŽãããµãŒãã¹ã«é©åãªã·ãªã¢ã«åæ¹æ³ãéžæãããšãããã©ãŒãã³ã¹ã«ãã©ã¹ã®åœ±é¿ããããŸãã
ãã®èšäºã§èª¬æããã·ãªã¢ã«åã®ã¢ãããŒãã¯ã次ã®ã·ã¹ãã ã®åæã«åºã¥ããŠããŸãã
- ãã£ãã·ã¥ã®å®¹éã¯å¶éãããŠãããæ°žç¶çãªã¹ãã¬ãŒãžãããã³ã¹ããããããŸãã Microsoft Azureã§ã¯ãå©çšå¯èœãªå¶éã倧ãããã£ãã·ã¥ã¯å€é¡ã®æ¯æããäºæ³ãããŸãã
- ã·ãªã¢ã«åãããè¡šçŸã®å€§éã®ãã€ãã¯ãæžã蟌ã¿/èªã¿åãã®ã³ã¹ãã ãã§ãªãããããã¯ãŒã¯ãä»ããããŒã¿ã®è»¢éã®ããã«ãããã£ãã·ã¥ã®çžäºäœçšæéã«æªåœ±é¿ãåãŒããŸãã
- ã·ãªã¢ã©ã€ãºå¯èœãªãªããžã§ã¯ãã®æ§æã¯æéçã«å®å®ããŠããããµãŒãã¹ãšãã£ãã·ã¥ã®ææè ã®å®å šãªå¶åŸ¡äžã«ãããŸãã å€éšããã®ã·ãªã¢ã«åãããããŒã¿ã䜿çšããå Žåãããããããã£ãŒã«ãã®äºæããªãå€èŠ³ãåé€ããŸãã¯äžŠã¹æ¿ãã¯çºçããŸããã
- ãã£ãã·ã¥ã¯æé©åããŒã«ã§ããããªããžã§ã¯ãã®äžæçãªã¹ãã¬ãŒãžã§ãã ãã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ã«ççŸãŸãã¯åé¡ãããå Žåããã£ãã·ã¥ããå€ããªããžã§ã¯ããåé€ããŠæ°ãããªããžã§ã¯ããšçœ®ãæããããšã¯å€§ããªåé¡ã§ã¯ãããŸããã
ãã®ãããªèæ¯ã«å¯ŸããŠãBinaryFormatterãå«ããã¹ãŠã®éåžžã®ã·ãªã¢ã©ã€ã¶ãŒã«ãã£ãŠä¿åããããã£ãŒã«ããã¯ã©ã¹ãããã³ã¢ã»ã³ããªã«é¢ããã¡ã¿ããŒã¿ã®ã·ãªã¢ã«åãããè¡šçŸããé€å€ãããããããªãã®ãã€ããç¯çŽããããšã¯é åçãªã¢ã€ãã¢ã®ããã§ãã æåŸã«ãææè ããã£ãŒã«ãã®æ§æã«ã€ããŠãã¹ãŠãç¥ã£ãŠããå Žåãããšãã°ãåã«ç¹å®ã®é åºã§è¡ããã©ãŒãããããŠãæ§æã«æããã«ãªãæåã§ããããåé¢ããããšãé²ãã®ã¯äœã§ããïŒ
"7c9e6679-7425-40de-944b-e07fc1f90ae7|48972|Alice in Wonderland"
ãã®ã¢ãããŒãã«ã¯ããçšåºŠã®ç²ŸåºŠãå¿ èŠã§ãããæ害ãšã¯èšããŸããã
ããã«é²ãã å Žåãã»ãã¬ãŒã¿ãªãã§ãæååã«ãã©ãŒãããããã«è¡ãããšãã§ããŸãïŒä»»æã®ã¿ã€ãã¯ã¡ã¢ãªå ã§ãã€ãã®ã·ãŒã±ã³ã¹ãšããŠè¡šãããããããã£ã®ã¿ã€ããç¥ã£ãŠããå Žåãå¿ èŠãªé·ãã®ãã€ãã®é åãèªã¿æžããã/ããå€æããããšãã§ããŸãç®çã®ã¿ã€ãã®å€ã æååãé åãªã©ãé·ããåºå®ãããŠããªãåã®å Žåãã·ãªã¢ã«åãããå€ã®åã«å«ãŸãããã€ãæ°/èŠçŽ æ°ãæå®ã§ããŸãã ã«ã¹ã¿ã ã¯ã©ã¹ãŸãã¯æ§é ã®ã¿ã€ããæã€ããããã£ã䜿çšãããšãç¹ã«åŸªç°ãªã³ã¯ã远跡ããå¿ èŠãããå Žåãç¶æ³ã¯ããè€éã«ãªããŸãããã®åçŽãªã±ãŒã¹ã§ã¯ããããã¯ãŸã èæ ®ãããŠããŸããã ïŒãã ããããã¯ããããååçã«å®çŸäžå¯èœã§ããããšãæå³ãããã®ã§ã¯ãããŸããïŒã
ãã£ãã·ã¥ã«å€æ°ã®ãã£ãŒã«ããæã€å€æ°ã®ãªããžã§ã¯ããæ ŒçŽããå Žåãèšè¿°ãããååã«åŸã£ãŠã·ãªã¢ã«åã®ããã®ã³ãŒããæžãã®ã¯éå±ã§ããšã©ãŒããããããããŸãã ãªããžã§ã¯ãå šäœãä¿åããå¿ èŠãããå Žåããã®ãããªæäœã¯System.Reflectionåå空éã䜿çšããŠç°¡åã«èªååã§ããŸãã
public override void Serialize(TObject theObject, Stream stream) { foreach (var property in _properties) { var val = property.GetValue(theObject); if (property.PropertyType == typeof(byte)) { stream.WriteByte((byte)val); } else if (property.PropertyType == typeof(bool)) { var bytes = BitConverter.GetBytes((bool)val); stream.Write(bytes, 0, bytes.Length); } else if (property.PropertyType == typeof(int)) { var bytes = BitConverter.GetBytes((int)val); stream.Write(bytes, 0, bytes.Length); } else if (property.PropertyType == typeof(Guid)) { var bytes = ((Guid)val).ToByteArray(); stream.Write(bytes, 0, bytes.Length); } ... } } public override TObject Deserialize(Stream stream) { var theObject = Activator.CreateInstance<TObject>(); foreach (var property in _properties) { object val; if (property.PropertyType == typeof(byte)) { val = stream.ReadByte(); } var bytesCount = TypesInfo.GetBytesCount(type); var valueBytes = new byte[bytesCount]; stream.Read(valueBytes, 0, valueBytes.Length); if (property.PropertyType == typeof(bool)) { val = BitConverter.ToBoolean(valueBytes, 0); } else if (property.PropertyType == typeof(int)) { val = BitConverter.ToInt32(valueBytes, 0); } else if (property.PropertyType == typeof(Guid)) { val = new Guid(valueBytes); } ... property.SetValue(theObject, val); } }
ãªããžã§ã¯ãã®ããããã£ã®æ§æãšãã®å€æŽ
MSDN 㯠ãã¢ã«ãã¡ãããé ãŸãã¯å®£èšé ã§Type.GetPropertiesïŒïŒã¡ãœããã«ããããããã£ã®æ»ãå€ãä¿èšŒããªããšããäºå®ã«ãããããããè¿ãããé åãåããªããžã§ã¯ãåã®åãããŒãžã§ã³ã§ã®åŒã³åºããšç°ãªããšä¿¡ããçç±ã¯ãããŸããã ä¿¡é Œæ§ãé«ããããã«ããã®ã¡ãœããã1ååŒã³åºããŠãçµæã®ããããã£ã®é åããã©ã€ããŒããã£ãŒã«ãã«ä¿åããã·ãªã¢ã«åæäœãšéã·ãªã¢ã«åæäœã®äž¡æ¹ã§ããã«äœ¿çšã§ããŸãã ãã£ãã·ã¥ã¯éåžžãé·æéãã³ã¹ãããã§å®è¡ãããã·ã¹ãã ã§äœ¿çšãããäžåºŠã·ãªã¢ã©ã€ãºå¯èœã¿ã€ãã®ããããã£ã®åæåãªã¹ãã䜿çšããŠã·ãªã¢ã©ã€ã¶ãŒãäœæããããšãé·æéååšããŸãã ãããäžååã ãšæãããå Žåã¯ããµãŒãã¹ã®åèµ·åæã«ååæåããŠãã®ãªã¹ãããã£ã¹ã¯ã«è¿œå ä¿åããããšãå¯èœã§ãããããã¯äžå¿ èŠãªäºé²çã®ããã§ãã
ããã§ããããããã£ã®æ§æãååãã¿ã€ãããŸãã¯çžå¯Ÿçãªå Žæãå€æŽãããšãå€ãããŒãžã§ã³ãæ£ãããã·ãªã¢ã©ã€ãºã§ããªããªããŸãã ãã ãã説æãããŠããã¢ã€ãã¢ã¯æ°žç¶çãªããŒã¿ããŒã¹ã§ã¯ãªããã£ãã·ã¥ã«ããŒã¿ãæ ŒçŽããããšãç®çãšããŠãããããççŸã«å¯ŸåŠããæãç°¡åãªæ¹æ³ã¯ãå€ããã€ãè¡šçŸãç¡å¹ã«ããæ°ããã·ãªã¢ã«åããããªããžã§ã¯ãã«çœ®ãæããããšã§ãã ããè€éãªã¢ãããŒããå¯èœã§ããããšãã°ãå¥ã®AppDomainã䜿çšããŠãå€ãããŒãžã§ã³ã®ã¿ã€ããããŒããããªããžã§ã¯ãããã·ãªã¢ã©ã€ãºããæ°ãããªããžã§ã¯ãã®ããããã£ãå ¥åããåãããŒã§ã·ãªã¢ã«åããŠä¿åããŸãã ãã ãããã®èšäºã§ã¯ããããéæããè©Šã¿ã¯è¡ãããŠããŸããã
ãããã®å Žåã§ãããªããžã§ã¯ãã®ã¿ã€ãã®å€æŽã远跡ããã«ã¯ãã·ãªã¢ã«åããã»ã¹ã«ããŒãžã§ã³ç®¡çã®ãªãã·ã§ã³ãå«ããå¿ èŠããããŸãã ããšãã°ããªããžã§ã¯ãèªäœã®ãã€ãã®åã«ããªããžã§ã¯ãã宣èšãããŠããã¢ã»ã³ããªããŒãžã§ã³ãèšè¿°ã§ããŸãã
public virtual string GetTypeVersion() { return typeof(TObject).Assembly.GetName().Version.ToString(); }
var reflectionSerializer = new ReflectionCompactSerializer<Entity>(); typeVersion = reflectionSerializer.GetTypeVersion(); reflectionSerializer.WriteVersion(stream, typeVersion); reflectionSerializer.Serialize(originalEntity, stream); var version = reflectionSerializer.ReadObjectVersion(stream); deserializedEntity = reflectionSerializer.Deserialize(stream);
ã¡ã¢ãªã«çµæãä¿åããŠGetPropertiesïŒïŒã¡ãœããã1åã ãåŒã³åºãããå€ãã®ç°ãªããªããžã§ã¯ããã·ãªã¢ã«åããå Žåããªããžã§ã¯ãã®ã¿ã€ããšååŸããããããã£ãªã¹ããäœããã®æ¹æ³ã§æ¯èŒããå¿ èŠããããŸãã ãããè¡ãã«ã¯ããã£ã¯ã·ã§ããªã®TypeâPropertyInfo []ã䜿çšããããGenericsã䜿çšããŠã·ãªã¢ã«åå¯èœãªåã¿ã€ãã«ç¹åããã·ãªã¢ã©ã€ã¶ãŒãéžæããŸãã 2çªç®ã®ã¢ãããŒãã¯äž»èŠ³çã«ãã䟿å©ã«èŠããŸãã
public class ReflectionCompactSerializer<TObject> : CompactSerializerBase<TObject> where TObject: class, new () { private readonly PropertyInfo[] _properties = typeof(TObject).GetProperties(BindingFlags.Instance | BindingFlags.Public); ... }
ããçç£çãªã¢ãããŒã
ãã®ã¿ã¹ã¯ã®ã³ã³ããã¹ãã§Reflectionã䜿çšãããšãã«çºçãã次ã®åé¡ã¯ãããã©ãŒãã³ã¹ã§ãããªãã¬ã¯ã·ã§ã³ã¯é«éã¡ã«ããºã ãšã¯èŠãªãããŸããã§ããã Sasha GoldshteinãDima ZurbalevãIdo Flatowãªã©ã®.Netã¢ããªã±ãŒã·ã§ã³ã®æé©åã«é¢ããæžç±ã§ã¯ã ãPro .Net PerformanceïŒOptimize Your CïŒApplicationsãããã³Ben Watson ãWriting High-Performance .NET Codeãã® 1ã€ãšããŠãã³ãŒããçæããããã«ãããšãã°åå空éSystem.Reflection.Emitã䜿çšããŠããªãã¬ã¯ã·ã§ã³ãšã«ã¹ã¿ã ã·ãªã¢ã©ã€ã¶ãŒã®äœæãææ¡ãããŠããŸãã ãã®ã¢ãããŒãã®ã¢ã€ãã¢ã¯ãããããã£ã®çµæãªã¹ãããã³ãŒããããã«äœæããããšã§ããã€ãŸããåããããã£ã®å€ã亀äºã«åãåãããã€ãã¹ããªãŒã ã«æžã蟌ã¿ãèªã¿åããå€æãå€ã®èšå®ãªã©ãè¡ãäžé£ã®åœä»€ã§ãã
System.Reflection.Emitåå空éã®ILGeneratorã¯ã©ã¹ã«ã¯ãDynamicMethodã¯ã©ã¹ã䜿çšããŠå®è¡æã«ã³ã³ãã€ã«ã§ããMSILäžéèšèªåœä»€ãäœæã§ããå€æ°ã®ã¡ãœãããå«ãŸããŠããŸãã äžè¬çã«ã¯ã次ã®ããã«ãªããŸãã
public static EmitSerializer<TObject> Generate<TObject>() where TObject : class, new() { var propertiesWriter = new DynamicMethod( "WriteProperties", null, new Type[] { typeof(Stream), typeof(TObject) }, typeof(EmitSerializer<TObject>)); var writerIlGenerator = propertiesWriter.GetILGenerator(); var writerEmitter = new CodeEmitter(writerIlGenerator); var propertiesReader = new DynamicMethod( "ReadProperties", null, new Type[] { typeof(Stream), typeof(TObject) }, typeof(EmitSerializer<TObject>)); var readerIlGenerator = propertiesReader.GetILGenerator(); var readerEmitter = new CodeEmitter(readerIlGenerator); var properties = typeof(TObject) .GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach(var property in properties) { if (property.PropertyType == typeof(byte)) { writerEmitter.EmitWriteBytePropertyCode(property); readerEmitter.EmitReadBytePropertyCode(property); } else if (property.PropertyType == typeof(Guid)) { writerEmitter.EmitWriteGuidPropertyCode(property); readerEmitter.EmitReadGuidPropertyCode(property); } ⊠} var writePropertiesDelegate = (Action<Stream,TObject>)propertiesWriter .CreateDelegate(typeof(Action<Stream, TObject>)); var readPropertiesDelegate = (Action<Stream, TObject>)propertiesReader .CreateDelegate(typeof(Action<Stream, TObject>)); return new EmitSerializer<TObject>( writePropertiesDelegate, readPropertiesDelegate); } }
ãã¡ããããå ±éã®æ©èœããè¶ ããŠãæãé£ãããŠèå³æ·±ãéšåã¯ãEmitWriteNNNPropertyCode / EmitReadNNNPropertyCodeã¡ãœããã®å®è£ ã§ãã
MSILã¯ãé«ã¬ãã«ã®ã¢ã»ã³ãã©ãã§ãããILGenerator.EmitïŒOpCodeïŒã¡ãœãããåŒã³åºããŠãç¹ã«éæ¥çãªæ¹æ³ã§æžã蟌ãããšã¯ã§ãããã³ãŒãã®èªã¿åããé£ããå ŽåããããŸãã
äžèšã®æ¬ã®ããããã§äžããããããªãã¯ã¯ããã§åœ¹ç«ã¡ãŸãïŒILã³ãŒãå šäœãæåããæžãå¿ èŠã¯ãããŸããã CïŒã§ãã¯ãŒã¯ããäœæããããã䜿çšããŠã¢ã»ã³ããªãäœæããILã§ãããéã¢ã»ã³ãã«ããçµæã®ãªãã¡ã¬ã³ã¹å®è£ ãèŠãŠãããŒãºã«å¿ããŠäžè¬åããããšã¯éåžžã«å¯èœã§ãã
Windowsã.Netã¢ã»ã³ããªããILã³ãŒããååŸã§ããéã¢ã»ã³ãã©ãŒãå€æ°ãããŸãïŒildasmãdotPeekãILSpyãªã©ãããããMicrosoftã®OSã§èµ·åããããã®ãããžã§ã¯ãã¯ãã§ã«Linuxã§æžãããŠããŸããïŒè¯ãã§ãã NET Coreã¯å¯èœã§ãïŒãéã¢ã»ã³ãã©ã®éžæã¯ããã»ã©å€§ãããããŸããã ãã ãããã®ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã§ã¯ãç¹ã«monodisã®ããŒã«ã䜿çšã§ããŸãã 次ã®ã³ãã³ãã§monodisã䜿çšããŠãdllã¢ã»ã³ããªããILã®ããã¹ããã¡ã€ã«ãšãœãŒã¹ã³ãŒããååŸã§ããŸãã
monodis < > --output=< >
æãåçŽãªåã®äžè¬çãªã·ãªã¢ã«å
çæãããã·ãªã¢ã©ã€ã¶ãŒã«ãã£ãŠå®è¡ããããã¹ãŠã®ã¢ã¯ã·ã§ã³ã¯ãå ã®ãªãã¬ã¯ã·ã§ã³ã·ãªã¢ã©ã€ã¶ãŒã®æäœã«äŒŒãŠãããäžèŠãããšæãããããããEmitãä»ããŠç°¡åã«ç¹°ãè¿ãããšãã§ããŸãã ããšãã°ãintåã®ããããã£ã®å€ãåãåãããã®ãã€ããã¹ããªãŒã ã«æžã蟌ããã¯ãŒã¯ããŒã¹ãã¯æ¬¡ã®ããã«ãªããŸãã
private static void WritePrimitiveTypeProperty(Stream stream, Entity entity) { var index = entity.Index; var valueBytes = BitConverter.GetBytes(index); stream.Write(valueBytes, 0, valueBytes.Length); }
ã¢ã»ã³ããªããã³éã³ã³ãã€ã«åŸã察å¿ããILã³ãŒãã«ã¯æ¬¡ã®æ瀺ãå«ãŸããŸãã
.method private static hidebysig default void WritePrimitiveTypeProperty (class [mscorlib]System.IO.Stream 'stream', class SourcesForIL.Entity entity) cil managed { // Method begins at RVA 0x241c // Code size 28 (0x1c) .maxstack 4 .locals init ( int32 V_0, unsigned int8[] V_1) IL_0000: nop IL_0001: ldarg.1 IL_0002: callvirt instance int32 class SourcesForIL.Entity::get_Index() IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: call unsigned int8[] class [mscorlib]System.BitConverter::GetBytes(int32) IL_000e: stloc.1 IL_000f: ldarg.0 IL_0010: ldloc.1 IL_0011: ldc.i4.0 IL_0012: ldloc.1 IL_0013: ldlen IL_0014: conv.i4 IL_0015: callvirt instance void class [mscorlib]System.IO.Stream::Write(unsigned int8[], int32, int32) IL_001a: nop IL_001b: ret }
ãŸããåå空éReflection.Emitã䜿çšããŠãããç¹°ãè¿ãã³ãŒãã¯ãILGeneratorã¡ãœããã®æ¬¡ã®ã·ãŒã±ã³ã¹ãåŒã³åºããŸãã
var byteArray = _ilGenerator.DeclareLocal(typeof(byte[])); // load object under serialization onto the evaluation stack _ilGenerator.Emit(OpCodes.Ldarg_1); // get property value _ilGenerator.EmitCall(OpCodes.Callvirt, property.GetMethod, null); // get value's representation in bytes _ilGenerator.EmitCall(OpCodes.Call, BitConverterMethodsInfo.ChooseGetBytesOverloadByType(valueType), null); // save the bytes array from the stack in local variable _ilGenerator.Emit(OpCodes.Stloc, byteArray); // load stream parameter onto the evaluation stack _ilGenerator.Emit(OpCodes.Ldarg_0); // load bytesCount array _ilGenerator.Emit(OpCodes.Ldloc_S, bytesArray); // load offset parameter == 0 onto the stack _ilGenerator.Emit(OpCodes.Ldc_I4_0); // load bytesCount array _ilGenerator.Emit(OpCodes.Ldloc_S, bytesArray); // calculate the array length _ilGenerator.Emit(OpCodes.Ldlen); // convert it to Int32 _ilGenerator.Emit(OpCodes.Conv_I4); // write array to stream _ilGenerator.EmitCall(OpCodes.Callvirt, StreamMethodsInfo.Write, null);
ããããã£ã®å€ã®ååŸã¯ãproperty.GetMethodã䜿çšããŠãã¹ãŠã®ã¿ã€ãã§åãã§ããããšã«æ³šæããŠãã ããã åæ§ã«ããã®å€ã®ãã€ãé åãžã®å€æã¯ç°¡åã«äžè¬åã§ããŸããMethodInfoåã®é©åãªåŒæ°ã䜿çšããã ãã§ãã ãããã£ãŠãåããžã§ãã¬ãŒã¿ãŒé¢æ°ã¯ãæž¡ããããã€ãã®é åãååŸããæ¹æ³ã«å¿ããŠãç°ãªãã¿ã€ãã®ããããã£ãã·ãªã¢ã«åããã³ãŒããäœæã§ããŸãã
System.BitConverterã¯ã©ã¹ã«ã¯ãããã€ãã®çµã¿èŸŒã¿åã®ããã€ãã®ãªãŒããŒããŒããããGetBytesã¡ãœãããå«ãŸããŠããŸããããããã¹ãŠã®åã«å¯ŸããŠãBitConverterMethodsInfo.ChooseGetBytesOverloadByTypeïŒvalueTypeïŒã§å¿ èŠãªMethodInfoãªãã·ã§ã³ãéžæããããšã§ãã·ãªã¢ã«åæäœãåãæ¹æ³ã§å®è¡ã§ããŸãã
Reflectionã䜿çšããŠã察å¿ããã¡ãœããã®MedodInfoãªããžã§ã¯ããå床ååŸããå¿ èŠããããŸãããããã®ã¡ãœããã«ãã°ããã¢ã¯ã»ã¹ããã«ã¯ãéçèŸæžã«ä¿åããã®ãçã«ããªã£ãŠããŸãã
public static MethodInfo ChooseGetBytesOverloadByType(Type type) { if (_getBytesMethods.ContainsKey(type)) { return _getBytesMethods[type]; } var method = typeof(BitConverter).GetMethod("GetBytes", new Type[] { type }); if (method == null) { throw new InvalidOperationException("No overload for parameter of type " + type.Name); } _getBytesMethods[type] = method; return method; }
äžèšã®ã³ãŒãã䜿çšãããšãboolãshortãintãlongãushortãuintãulongãdoubleãfloatãcharãªã©ã®ããã€ãã®ã·ã¹ãã ã¿ã€ãã®ã³ãŒããçæã§ããŸãã
10é²æ°ãGUIDãããã³ãã€ãã®ã·ãªã¢ã«å
10é²æ°åã¯ããªããã£ãåã®ãªã¹ãããéžæãããŸãããSystem.BitConverterã«ãã€ãã®é åãååŸããããã®çµã¿èŸŒã¿ã¡ãœããã¯ãããŸããã ãããã£ãŠãå€æã¡ãœããã¯åå¥ã«å®è£ ããå¿ èŠããããŸãã
public static byte[] GetDecimalBytes(decimal value) { var bits = decimal.GetBits((decimal)value); var bytes = new List<byte>(); foreach (var bitsPart in bits) { bytes.AddRange(BitConverter.GetBytes(bitsPart)); } return bytes.ToArray(); } public static decimal BytesToDecimal(byte[] bytes, int startIndex) { var valueBytes = bytes.Skip(startIndex).ToArray(); if (valueBytes.Length != 16) throw new Exception("A decimal must be created from exactly 16 bytes"); var bits = new Int32[4]; for (var bitsPart = 0; bitsPart <= 15; bitsPart += 4) { bits[bitsPart/4] = BitConverter.ToInt32(valueBytes, bitsPart); } return new decimal(bits); }
Guidã¿ã€ãã®å ŽåãBitConverter.GetBytesã¡ãœããã®ãªãŒããŒããŒãããããŸãããããã®ãã€ãè¡šçŸã®ååŸã¯ç°¡åã§ã-Guid.ToByteArrayã¡ãœããã䜿çšããŸãã GUIDã«ã¯ããã€ãé åããå€ã埩å ããã³ã³ã¹ãã©ã¯ã¿ãŒããããŸãã
private static void WriteGuidProperty(Stream stream, Entity entity) { var id = entity.Id; var valueBytes = id.ToByteArray(); stream.Write(valueBytes, 0, valueBytes.Length); } private static void ReadGuidProperty(Stream stream, Entity entity) { var valueBytes = new byte[16]; stream.Read(valueBytes, 0, valueBytes.Length); entity.Id = new Guid(valueBytes); }
ãã€ãã䜿çšãããšãéåžžã«ç°¡åã«ãªããŸããStreamã¯ã©ã¹ã«ã¯ã1ãã€ããèªã¿æžãããããã®ç¹å¥ãªã¡ãœããããããŸãã
æ¥ä»ãšæå»ã®ã·ãªã¢ã«å
DateTimeåãšDateTimeOffsetåã§ã¯ãæéå€ã ãã§ãªããããããKindãã£ãŒã«ããšOffsetãã£ãŒã«ãã«ãã£ãŠã決å®ããããããäºæ ã¯ããå°ãè€éã§ãã ãããã®ãã£ãŒã«ãã¯ãæéèªäœãšäžç·ã«èªã¿æžãããå¿ èŠããããŸãã ããšãã°ãDateTimeOffsetå€æ°ã®å€ãæ ŒçŽããILã³ãŒãã®çæã¯æ¬¡ã®ããã«ãªããŸãã
private void EmitWriteDateTimeOffsetVariable(LocalBuilder dateTimeOffset) { var offset = _ilGenerator.DeclareLocal(typeof(TimeSpan)); var dateTimeTicks = _ilGenerator.DeclareLocal(typeof(long)); var dateTimeTicksByteArray = _ilGenerator.DeclareLocal(typeof(byte[])); var offsetTicksByteArray = _ilGenerator.DeclareLocal(typeof(byte[])); // load the variable address to the stack _ilGenerator.Emit(OpCodes.Ldloca_S, dateTimeOffset); // call method to get Offset property _ilGenerator.EmitCall(OpCodes.Call, DateTimeOffsetMembersInfo.OffsetProperty, null); // save it to local variable _ilGenerator.Emit(OpCodes.Stloc, offset); // load the variable address to the stack _ilGenerator.Emit(OpCodes.Ldloca_S, offset); // call method to get offset Ticks property _ilGenerator.EmitCall(OpCodes.Call, TimeSpanMembersInfo.TicksProperty, null); // convert it to byte array _ilGenerator.EmitCall(OpCodes.Call, GetInt64BytesMethodInfo, null); // save it to local variable _ilGenerator.Emit(OpCodes.Stloc, offsetTicksByteArray); EmitWriteBytesArrayToStream(offsetTicksByteArray); // load the dateTimeOffset variable address to the stack _ilGenerator.Emit(OpCodes.Ldloca_S, dateTimeOffset); // call method to get Ticks property _ilGenerator.EmitCall(OpCodes.Call, DateTimeOffsetMembersInfo.TicksProperty, null); // save it to local variable _ilGenerator.Emit(OpCodes.Stloc, dateTimeTicks); // load the variable address to the stack _ilGenerator.Emit(OpCodes.Ldloc, dateTimeTicks); // convert it to byte array _ilGenerator.EmitCall(OpCodes.Call, GetInt64BytesMethodInfo, null); // save it to local variable _ilGenerator.Emit(OpCodes.Stloc, dateTimeTicksByteArray); EmitWriteBytesArrayToStream(dateTimeTicksByteArray); }
ãã€ãåäœã§ã®åã®é·ãã®æ±ºå®
äžèšã®ãã¹ãŠã®åã®éã·ãªã¢ã«åã¯å¯Ÿç§°çã§ããã察å¿ãããã€ãé åãèªã¿åãã«ã¯ããã®é·ããç¥ãå¿ èŠããããŸãã å®è¡æã«ãããããã£ã¿ã€ãã¯Typeã¯ã©ã¹ã®å€ãšããŠäœ¿çšå¯èœã§ãããsizeofæäœãé©çšã§ããŸããã Marshal.SizeOfã¡ãœããã圹ã«ç«ã¡ãŸãããããã¯ãã¹ãŠã®ã¿ã€ãã«é©çšã§ããããã§ã¯ãªããã«ã¹ã¿ã ä¿åã®å®è£ ã«ãã£ãŠæžã蟌ãŸãããã€ãæ°ãè¿ããŸããã ãã ãããããã®å Žåã¯ãåçŽã«æ瀺çã«ãµã€ãºãè¿ãããšãã§ããŸãã
public static int GetBytesCount(Type propertyType) { if (propertyType == typeof(DateTime)) { return sizeof(long) + 1; } else if (propertyType == typeof(DateTimeOffset)) { return sizeof(long) + sizeof(long); } else if (propertyType == typeof(bool)) { return sizeof(bool); } else if(propertyType == typeof(char)) { return sizeof(char); } else if (propertyType == typeof(decimal)) { return 16; } else { return Marshal.SizeOf(propertyType); } }
ã·ãªã¢ã«åNullable <T>
Nullable <>ãã·ãªã¢ã«åããå Žåãæåã«ããããã£ã«nullãå«ãŸãããã©ãããå€æãããã©ã°ãæžã蟌ã¿ãå€ã空ã§ãªãå Žåã«ã®ã¿ãæ¢ã«å®è£ ãããŠããã¡ãœããã䜿çšããŠå€èªäœãæžã蟌ã¿ãŸãã
public void EmitWriteNullablePropertyCode(PropertyInfo property) { var nullableValue = _ilGenerator.DeclareLocal(property.PropertyType); var isNull = _ilGenerator.DeclareLocal(typeof(bool)); var isNullByte = _ilGenerator.DeclareLocal(typeof(byte)); var underlyingType = property.PropertyType.GetGenericArguments().Single(); var value = _ilGenerator.DeclareLocal(underlyingType); var valueBytes = _ilGenerator.DeclareLocal(typeof(byte[])); var nullableInfo = NullableInfo.GetNullableInfo(underlyingType); var nullFlagBranch = _ilGenerator.DefineLabel(); var byteFlagLabel = _ilGenerator.DefineLabel(); var noValueLabel = _ilGenerator.DefineLabel(); EmitLoadPropertyValueToStack(property); // save nullable value to local variable _ilGenerator.Emit(OpCodes.Stloc, nullableValue); // load address of the variable to stack _ilGenerator.Emit(OpCodes.Ldloca_S, nullableValue); // get HasValue property _ilGenerator.EmitCall(OpCodes.Call, nullableInfo.HasValueProperty, null); // load value '0' to stack _ilGenerator.Emit(OpCodes.Ldc_I4_0); // compare _ilGenerator.Emit(OpCodes.Ceq); // save to local boolean variable _ilGenerator.Emit(OpCodes.Stloc, isNull); // load to stack _ilGenerator.Emit(OpCodes.Ldloc, isNull); // jump to isNull branch, if needed _ilGenerator.Emit(OpCodes.Brtrue_S, nullFlagBranch); // load value '0' to stack _ilGenerator.Emit(OpCodes.Ldc_I4_0); // jump to byteFlagLabel _ilGenerator.Emit(OpCodes.Br_S, byteFlagLabel); _ilGenerator.MarkLabel(nullFlagBranch); // load value '1' to stack _ilGenerator.Emit(OpCodes.Ldc_I4_1); _ilGenerator.MarkLabel(byteFlagLabel); // convert to byte _ilGenerator.Emit(OpCodes.Conv_U1); // save to local variable _ilGenerator.Emit(OpCodes.Stloc, isNullByte); // load stream parameter to stack _ilGenerator.Emit(OpCodes.Ldarg_0); // load byte flag to the stack _ilGenerator.Emit(OpCodes.Ldloc, isNullByte); // write it to the stream _ilGenerator.EmitCall(OpCodes.Callvirt, StreamMethodsInfo.WriteByte, null); // load isNull flag to stack _ilGenerator.Emit(OpCodes.Ldloc, isNull); // load value '0' _ilGenerator.Emit(OpCodes.Ldc_I4_0); // compare _ilGenerator.Emit(OpCodes.Ceq); // jump to tne end, if no value presented _ilGenerator.Emit(OpCodes.Brfalse_S, noValueLabel); // load the address of the nullable to the stack _ilGenerator.Emit(OpCodes.Ldloca_S, nullableValue); // get actual value _ilGenerator.EmitCall(OpCodes.Call, nullableInfo.ValueProperty, null); EmitWriteValueFromStackToStream(underlyingType); _ilGenerator.MarkLabel(noValueLabel); }
æåååŠç
æåååã®å€ã®ãµã€ãºã¯åºå®ãããŠããããæ ŒçŽãããŠãããã€ãæ°ã¯äºåã«ããããŸããã ãã ããç¹å®ã®æååã®é·ãã¯ããããæ§æãããã€ããæžã蟌ãåã«ã¹ããªãŒã ã«ä¿åã§ããŸãã éã·ãªã¢ã«åããå ŽåããŸãæååã®é·ããæã€intãå«ããã€ãã®é åãèªã¿åãããã®é·ãã®å€ãååŸããŠããã察å¿ãããã€ãæ°ãèªã¿åãããšãã§ããŸãã NULLæååã®å Žåãå€ã-1ããæžã蟌ããšãé·ã0ã®ç©ºã®æååãšåºå¥ã§ããŸãã
Encoding.GetBytes / Encoding.GetStringã¡ãœããã䜿çšãããšãæååããã€ãé åã«å€æãããããã€ãé åããç°¡åã«å€æãããã§ããŸãã å€æŽã«ã€ããŠã¯ãã¬ã³ãŒãã§ã¯ãªããã¹ããªãŒã ããæååãèªã¿åãæ¹æ³ããããŸãã
private void EmitReadStringFromStreamToStack() { var bytesCoutArray = _ilGenerator.DeclareLocal(typeof(byte[])); var stringBytesCount = _ilGenerator.DeclareLocal(typeof(int)); var stringBytesArray = _ilGenerator.DeclareLocal(typeof(byte[])); var isNull = _ilGenerator.DeclareLocal(typeof(bool)); var isNotNullBranch = _ilGenerator.DefineLabel(); var endOfReadLabel = _ilGenerator.DefineLabel(); var propertyBytesCount = TypesInfo.GetBytesCount(typeof(int)); // push the amout of bytes to read onto the stack _ilGenerator.Emit(OpCodes.Ldc_I4, propertyBytesCount); // allocate array to store bytes _ilGenerator.Emit(OpCodes.Newarr, typeof(byte)); // stores the allocated array in the local variable _ilGenerator.Emit(OpCodes.Stloc, bytesCoutArray); // push the stream parameter _ilGenerator.Emit(OpCodes.Ldarg_0); // push the byte count array _ilGenerator.Emit(OpCodes.Ldloc, bytesCoutArray); // push '0' as the offset parameter _ilGenerator.Emit(OpCodes.Ldc_I4_0); // push the byte array again - to calculate its length _ilGenerator.Emit(OpCodes.Ldloc, bytesCoutArray); // get the length _ilGenerator.Emit(OpCodes.Ldlen); // convert the result to Int32 _ilGenerator.Emit(OpCodes.Conv_I4); // call the stream.Read method _ilGenerator.EmitCall(OpCodes.Callvirt, StreamMethodsInfo.Read, null); // pop amount of bytes read _ilGenerator.Emit(OpCodes.Pop); // push the bytes count array _ilGenerator.Emit(OpCodes.Ldloc, bytesCoutArray); // push '0' as the start index parameter _ilGenerator.Emit(OpCodes.Ldc_I4_0); // convert the bytes to Int32 _ilGenerator.EmitCall(OpCodes.Call, BytesToInt32MethodInfo, null); // save bytes count to local variable _ilGenerator.Emit(OpCodes.Stloc, stringBytesCount); // load it to the stack _ilGenerator.Emit(OpCodes.Ldloc, stringBytesCount); // put value '-1' to the stack _ilGenerator.Emit(OpCodes.Ldc_I4_M1); // compare bytes count and -1 _ilGenerator.Emit(OpCodes.Ceq); // save to boolean variable _ilGenerator.Emit(OpCodes.Stloc, isNull); // load to stack _ilGenerator.Emit(OpCodes.Ldloc, isNull); // if false, jump to isNotNullBranch _ilGenerator.Emit(OpCodes.Brfalse_S, isNotNullBranch); // push 'null' value _ilGenerator.Emit(OpCodes.Ldnull); // jump to the end of read fragment _ilGenerator.Emit(OpCodes.Br_S, endOfReadLabel); // not null string value branch _ilGenerator.MarkLabel(isNotNullBranch); // load bytes count to the stack _ilGenerator.Emit(OpCodes.Ldloc, stringBytesCount); // allocate array to store bytes _ilGenerator.Emit(OpCodes.Newarr, typeof(byte)); // save it to local variable _ilGenerator.Emit(OpCodes.Stloc, stringBytesArray); // push the stream parameter _ilGenerator.Emit(OpCodes.Ldarg_0); // load string bytes array to stack _ilGenerator.Emit(OpCodes.Ldloc, stringBytesArray); // push '0' as the start index parameter _ilGenerator.Emit(OpCodes.Ldc_I4_0); // load string bytes array to stack to get array length _ilGenerator.Emit(OpCodes.Ldloc, stringBytesArray); // get the length _ilGenerator.Emit(OpCodes.Ldlen); // convert the result to Int32 _ilGenerator.Emit(OpCodes.Conv_I4); // call the stream.Read method _ilGenerator.EmitCall(OpCodes.Callvirt, StreamMethodsInfo.Read, null); // pop amount of bytes read _ilGenerator.Emit(OpCodes.Pop); // load Encoding to stack _ilGenerator.EmitCall(OpCodes.Call, EncodingMembersInfo.EncodingGetter, null); // load string bytes _ilGenerator.Emit(OpCodes.Ldloc, stringBytesArray); // call Encoding.GetString() method _ilGenerator.EmitCall(OpCodes.Callvirt, EncodingMembersInfo.GetStringMethod, null); _ilGenerator.MarkLabel(endOfReadLabel); }
é åãšã³ã¬ã¯ã·ã§ã³ãæäœãã
é åã®ã·ãªã¢ã«åã«ã¯ãæååã®æäœã«äŒŒãã¢ãããŒãã䜿çšã§ããŸãããŸãããã®é·ããæžã蟌ã¿ïŒèªã¿åãïŒã次ã«é©åãªå埩åæ°ã®ã«ãŒãã§ãäžèšã§å®è£ ããåäžã®å€ãåŠçããæ¹æ³ã®1ã€1ã€ã§åèŠçŽ ãæžã蟌ã¿ãŸãïŒèªã¿åãïŒã
public void EmitReadArrayPropertyCode(PropertyInfo property) { var elementType = property.PropertyType.GetElementType(); var elementBytesArray = _ilGenerator.DeclareLocal(typeof(byte[])); var lengthBytes = _ilGenerator.DeclareLocal(typeof(byte[])); var arrayLength = _ilGenerator.DeclareLocal(typeof(int)); var array = _ilGenerator.DeclareLocal(property.PropertyType); var element = _ilGenerator.DeclareLocal(elementType); var index = _ilGenerator.DeclareLocal(typeof(int)); var isNullArrayLabel = _ilGenerator.DefineLabel(); var setPropertyLabel = _ilGenerator.DefineLabel(); var loopConditionLabel = _ilGenerator.DefineLabel(); var loopIterationLabel = _ilGenerator.DefineLabel(); // push deserialized object to stack _ilGenerator.Emit(OpCodes.Ldarg_1); EmitAllocateBytesArrayForType(typeof(int), lengthBytes); EmitReadByteArrayFromStream(lengthBytes); EmitConvertBytesArrayToPrimitiveValueOnStack(lengthBytes, typeof(int)); // save it to local variable _ilGenerator.Emit(OpCodes.Stloc, arrayLength); EmitJumpIfNoElements(arrayLength, isNullArrayLabel); // push array length to stack _ilGenerator.Emit(OpCodes.Ldloc, arrayLength); // create new array _ilGenerator.Emit(OpCodes.Newarr, elementType); // save it to the local variable _ilGenerator.Emit(OpCodes.Stloc, array); EmitZeroIndex(index); if (elementType != typeof(string)) { EmitAllocateBytesArrayForType(elementType, elementBytesArray); } // jump to the loop condition check _ilGenerator.Emit(OpCodes.Br_S, loopConditionLabel); _ilGenerator.MarkLabel(loopIterationLabel); if (elementType == typeof(string)) { EmitReadStringFromStreamToStack(); } else { EmitReadValueFromStreamToStack(elementType, elementBytesArray); } // save to local variable _ilGenerator.Emit(OpCodes.Stloc, element); // load array instance to stack _ilGenerator.Emit(OpCodes.Ldloc, array); // load element index _ilGenerator.Emit(OpCodes.Ldloc_S, index); // load the element to stack _ilGenerator.Emit(OpCodes.Ldloc_S, element); // set element to the array _ilGenerator.Emit(OpCodes.Stelem, elementType); EmitIndexIncrement(index); _ilGenerator.MarkLabel(loopConditionLabel); EmitIndexIsLessCheck(index, arrayLength); // jump to the iteration if true _ilGenerator.Emit(OpCodes.Brtrue_S, loopIterationLabel); // push filled array to stack _ilGenerator.Emit(OpCodes.Ldloc, array); // jump to SetProperty label _ilGenerator.Emit(OpCodes.Br_S, setPropertyLabel); _ilGenerator.MarkLabel(isNullArrayLabel); _ilGenerator.Emit(OpCodes.Ldnull); _ilGenerator.MarkLabel(setPropertyLabel); // call object's property setter _ilGenerator.EmitCall(OpCodes.Callvirt, property.SetMethod, null); }
é åã«å ããŠããããžã§ã¯ãã¯æ±çšã³ã¬ã¯ã·ã§ã³ãå®è£ ããŸãããªã¹ã<>ãªã¹ãã§ãã¹ããå®è¡ãããŸããããã³ãŒãã¯ã次ã®æ¡ä»¶ãæºããå Žåã«ã³ã¬ã¯ã·ã§ã³ããããã£ãåŠçãããããã«èšèšãããŠããŸãã
- ãã©ã¡ãŒã¿ãŒãªãã®ãããªãã¯ã³ã³ã¹ãã©ã¯ã¿ãŒããããŸãã
- ICollection <T>ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããŸãã
- Tã¯ãåè¿°ã®åçŽåã§ãã
ã³ã¬ã¯ã·ã§ã³ã®ã·ãªã¢ã«åãšã·ãªã¢ã«å解é€ã¯ãé åãšåæ§ã®æ¹æ³ã§å®è£ ãããICollection <>ã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ã«ããããŸãåä¿¡ããEnumerator-aã®MoveNextããã³Currentã®åŒã³åºãã«ããå©çšå¯èœãªAddãCountãGetEnumeratorã¡ãœããããã³ããããã£ã®äœ¿çšã«åãããŠèª¿æŽãããŸãã
ãã¹ããæ¯èŒãçµè«
ãã®èª¿æ»ã¯ãçµæã®ã·ãªã¢ã©ã€ã¶ãŒãæšæºãªãã·ã§ã³ãšæ¯èŒããªããšå®äºããŸãããè³éãè©äŸ¡ããããã«ãåè¿°ã®BinaryFormatterãšNewtonsoft JsonSerializerãæãäžè¬çãªã©ã€ãã©ãªå®è£ ã®1ã€ãšããŠéžã°ããŸããã Xmlã·ãªã¢ã«åã¯ãæããã«ãåé·ãã§ãããããèæ ®ãããŸããã§ããããã®æ¯èŒã¯ãã·ãªã¢ã«å/éã·ãªã¢ã«åæã®å¹³å1000åã®è©Šè¡ãšãã·ãªã¢ã«åãããè¡šçŸã®ãµã€ãºïŒãã€ãåäœïŒã«åºã¥ããŠããŸããå®éšã®ãªããžã§ã¯ãã«ã¯ãäžèšã®ãã¹ãŠã®ã¿ã€ãã®ããããã£ãå«ãŸããŠããããã®å®è£ ã§ãµããŒããããŠããªãããããã£ã¯å«ãŸããŠããŸããã
var originalEntity = new Entity { Name = "Name", ShortName = string.Empty, Description = null, Label = 'L', Age = 32, Index = -7, IsVisible = true, Price = 225.87M, Rating = 4.8, Weigth = 130, ShortIndex = short.MaxValue, LongIndex = long.MinValue, UnsignedIndex = uint.MaxValue, ShortUnsignedIndex = 25, LongUnsignedIndex = 11, Id = Guid.NewGuid(), CreatedAt = DateTime.Now, CreatedAtUtc = DateTime.UtcNow, LastAccessed = DateTime.MinValue, ChangedAt = DateTimeOffset.Now, ChangedAtUtc = DateTimeOffset.UtcNow, References = null, Weeks = new List<short>() { 3, 12, 24, 48, 53, 61 }, PricesHistory = new decimal[] { 225.8M, 226M, 227.87M, 224.87M }, BitMap = new bool[] { true, true, false, true, false, false, true, true }, ChildrenIds = new Guid [] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }, Schedule = new DateTime [] { DateTime.Now.AddDays(-1), DateTime.Now.AddMonths(2), DateTime.Now.AddYears(10) }, Moments = new DateTimeOffset [] { DateTimeOffset.UtcNow.AddDays(-5), DateTimeOffset.Now.AddDays(10) }, Tags = new List<string> { "The quick brown fox jumps over the lazy dog", "Reflection.Emit", string.Empty, "0" }, AlternativeId = Guid.NewGuid() };
ãçŽç²ãªããªãã¬ã¯ã·ã§ã³ã·ãªã¢ã©ã€ã¶ãŒã§ãããããäžè¬çã§è€éãªã¿ã¹ã¯ã«éç¹ã眮ããŠããããããã®ãããªãªããžã§ã¯ãã§ã¯æšæºãªãã·ã§ã³ãããåªããçµæã瀺ããŠããããšã«æ³šæããŠãã ãããEmitSerializerã®çµæã¯ããã«åªããŠããŸããïŒçæãããã³ãŒãã1åã³ã³ãã€ã«ããã®ã«ããã£ãæéãé€ãïŒã枬å®äžã«åŸãããå€ïŒ
Serializer | Average elapsed, ms | Size, bytes ------------------------------------------------------------------------------- EmitSerializer | 9.9522 | 477 ------------------------------------------------------------------------------- ReflectionSerializer | 22.9454 | 477 ------------------------------------------------------------------------------- BinaryFormatter | 246.4836 | 1959 ------------------------------------------------------------------------------- Newtonsoft JsonSerializer | 87.1893 | 1156 EmitSerializer compiled in: 104.5019 ms
ãœãŒã¹ã³ãŒã
ãœãªã¥ãŒã·ã§ã³ã®ãœãŒã¹ã³ãŒãã¯Githubã«ãããŸãã
ãã ããå®è£ ã¯ãã®ãŸãŸã§æäŸããã誀ããä¿¡é Œæ§ã®ä¿èšŒã¯ãããŸãããäœè ã¯ãçŸæç¹ã§ã¯ããã®ã¢ã€ãã¢ãçãŸããæ çµã¿ã®äžã§ãããžã§ã¯ããå»ãããæŠéæ¡ä»¶ãã§ãã¹ããå®æœããæ©äŒããããŸããã§ããã
ã³ãŒãã¯.NET Core 2.0ã§äœæãããLinux Ubuntu 16.04 LTS OSã§ã³ã³ãã€ã«ããã³ãã¹ããããŸããã