
ãã£ãã·ã¥ã®ãªãææ°ã®ãµãŒãã¹ã§ã¯ãã©ãã«ããããŸãããæ°žç¶ããŒã¿ããŒã¹å
ã®ããŒã¿ãžã®ã¢ã¯ã»ã¹ã¯é·ããŠè²»çšã®ãããããžãã¹ãªã®ã§ãæãé »ç¹ã«äœ¿çšãããããŒã¿ã«äžéã¹ãã¬ãŒãžãè¿œå ãããšãé床ã倧å¹
ã«åäžããŸãã æ
å ±ã¯ãã©ã€ã³ããªã¹ããã»ãã·ã§ã³ç¶æ
ãªã©ãããŸããŸãªæ¹æ³ã§ããŸããŸãªåœ¢åŒã§ãã£ãã·ã¥ã«ä¿æã§ããŸãã ãã®èšäºã§ã¯ããã¹ããããã¯ã©ã¹ãšåŸªç°åç
§ãæããªãããã©ããããªããžã§ã¯ãããã£ãã·ã¥ã«ä¿åããæ¹æ³ã®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[]));
ããããã£ã®å€ã®ååŸã¯ã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[]));
ãã€ãåäœã§ã®åã®é·ãã®æ±ºå®
äžèšã®ãã¹ãŠã®åã®éã·ãªã¢ã«åã¯å¯Ÿç§°çã§ããã察å¿ãããã€ãé
åãèªã¿åãã«ã¯ããã®é·ããç¥ãå¿
èŠããããŸãã å®è¡æã«ãããããã£ã¿ã€ãã¯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);
æåååŠç
æåååã®å€ã®ãµã€ãºã¯åºå®ãããŠããããæ ŒçŽãããŠãããã€ãæ°ã¯äºåã«ããããŸããã ãã ããç¹å®ã®æååã®é·ãã¯ããããæ§æãããã€ããæžã蟌ãåã«ã¹ããªãŒã ã«ä¿åã§ããŸãã éã·ãªã¢ã«åããå ŽåããŸãæååã®é·ããæã€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));
é
åãšã³ã¬ã¯ã·ã§ã³ãæäœãã
é
åã®ã·ãªã¢ã«åã«ã¯ãæååã®æäœã«äŒŒãã¢ãããŒãã䜿çšã§ããŸãããŸãããã®é·ããæžã蟌ã¿ïŒèªã¿åãïŒã次ã«é©åãªå埩åæ°ã®ã«ãŒãã§ãäžèšã§å®è£
ããåäžã®å€ãåŠçããæ¹æ³ã®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();
é
åã«å ããŠããããžã§ã¯ãã¯æ±çšã³ã¬ã¯ã·ã§ã³ãå®è£
ããŸãããªã¹ã<>ãªã¹ãã§ãã¹ããå®è¡ãããŸããããã³ãŒãã¯ã次ã®æ¡ä»¶ãæºããå Žåã«ã³ã¬ã¯ã·ã§ã³ããããã£ãåŠçãããããã«èšèšãããŠããŸãã- ãã©ã¡ãŒã¿ãŒãªãã®ãããªãã¯ã³ã³ã¹ãã©ã¯ã¿ãŒããããŸãã
- 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ã§ã³ã³ãã€ã«ããã³ãã¹ããããŸããã