一直使用 MongoDb 的 Samus C#驱动。

其有一个缺陷,就是无法支持struct的读写。

但是一般数据都用Class包装,所以也没有太在意。

随着这些天尝试写入 KLineData 时,遇到了非常龌龊的问题。

KLineData这个Class内部有一个TICK[4] 这样一个数组,TICK是一个结构类型

Samus可以顺利的写入KLineData

但是读取时,立刻发生了异常。

查看内部实现,发现其用Emit做的ORM,代码如下:

1.创建Map

  1. private ExtendedPropertiesMap CreateExtendedPropertiesMap(Type classType){
  2. var extPropMember = _profile.FindExtendedPropertiesMember(classType);
  3. if(extPropMember == null)
  4. return null;
  5.  
  6. return new ExtendedPropertiesMap(
  7. extPropMember.Name,
  8. extPropMember.GetReturnType(),
  9. MemberReflectionOptimizer.GetGetter(extPropMember),
  10. MemberReflectionOptimizer.GetSetter(extPropMember));
  11. }

其中GetSetter代码如下

  1. public static Action<object, object> GetSetter(MemberInfo memberInfo)
  2. {
  3. if(memberInfo == null)
  4. throw new ArgumentNullException("memberInfo");
  5. if(memberInfo.MemberType != MemberTypes.Field && memberInfo.MemberType != MemberTypes.Property)
  6. throw new ArgumentException("Only fields and properties are supported.", "memberInfo");
  7.  
  8. if(memberInfo.MemberType == MemberTypes.Field)
  9. return GetFieldSetter(memberInfo as FieldInfo);
  10.  
  11. if(memberInfo.MemberType == MemberTypes.Property)
  12. return GetPropertySetter(memberInfo as PropertyInfo);
  13.  
  14. throw new InvalidOperationException("Can only create setters for fields or properties.");
  15. }

我们关注其中的Field的Emit反射

  1. public static Action<object, object> GetFieldSetter(FieldInfo fieldInfo)
  2. {
  3. if(fieldInfo == null)
  4. throw new ArgumentNullException("fieldInfo");
  5.  
  6. var key = CreateKey(fieldInfo);
  7.  
  8. Action<object, object> setter;
  9.  
  10. lock (SyncObject)
  11. {
  12. if (SetterCache.TryGetValue(key, out setter))
  13. return setter;
  14. }
  15.  
  16. if (fieldInfo.IsInitOnly || fieldInfo.IsLiteral)
  17. throw new InvalidOperationException("Cannot create a setter for a readonly field.");
  18.  
  19. var sourceType = fieldInfo.DeclaringType;
  20. var method = new DynamicMethod("Set" + fieldInfo.Name, null, new[] {typeof (object), typeof (object)}, true);
  21. var gen = method.GetILGenerator();
  22.  
  23. gen.Emit(OpCodes.Ldarg_0);
  24. gen.Emit(OpCodes.Castclass, sourceType);
  25. gen.Emit(OpCodes.Ldarg_1);
  26. gen.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
  27. gen.Emit(OpCodes.Stfld, fieldInfo);
  28. gen.Emit(OpCodes.Ret);
  29.  
  30. setter = (Action<object, object>) method.CreateDelegate(typeof (Action<object, object>));
  31.  
  32. lock (SyncObject)
  33. {
  34. SetterCache[key] = setter;
  35. }
  36.  
  37. return setter;
  38. }

gen.Emit(OpCodes.Ldarg_0); // 把参数0入栈

            gen.Emit(OpCodes.Castclass, sourceType);//把参数0的类型转为sourceType :   x as NewType

            gen.Emit(OpCodes.Ldarg_1);// 把参数1入栈

            gen.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);//把参数1的类型强制转换为FieldType:  (NewType)x

            gen.Emit(OpCodes.Stfld, fieldInfo);// SetField( 参数0,参数1 )

            gen.Emit(OpCodes.Ret);// 返回

以上代码有一个问题,就是要求参数0是Class,如果是Value是有异常的,即使可行也是没有意义的,因为ValueType是指传递

setter函数的设计模式(<object,object>) 天然就无法处理Value

解决办法:

  1. public void AddProperty(string name, object value)
  2. {
  3. #region Original Codes
  4. //var memberMap = _classMap.GetMemberMapFromAlias(name);
  5. //if (memberMap != null)
  6. // memberMap.SetValue(_instance, value);
  7. //else if ((!_classMap.HasDiscriminator || _classMap.DiscriminatorAlias != name) && _extendedProperties != null)
  8. // _extendedProperties.Add(name, value);
  9. #endregion
  10. #region norsd Codes
  11. if(_bIsClass)
  12. {
  13. var memberMap = _classMap.GetMemberMapFromAlias(name);
  14. if (memberMap != null)
  15. memberMap.SetValue(_instance, value);
  16. else if ((!_classMap.HasDiscriminator || _classMap.DiscriminatorAlias != name) && _extendedProperties != null)
  17. _extendedProperties.Add(name, value);
  18. }
  19. else
  20. {
  21. _SetStructValue(name, ref _instance, value);
  22. }
  23. #endregion
  24. }

注意_bIsClass就走原始流程,如果是Struct就走 _SetStructValue 流程

下面贴出整个类的代码

架构:

设置一个全局静态变量

readonly static System.Collections.Generic.Dictionary<System.Reflection.FieldInfo, SETSTVALUE> _s_dtStSetter = new Dictionary<System.Reflection.FieldInfo, SETSTVALUE>();

用于缓存SetStructValue函数

同时一个类私有变量readonly System.Collections.Generic.Dictionary<string, SETSTVALUE> _dtStSetter = new Dictionary<string, SETSTVALUE>();

用于快速在FieldInfo.Name -> SetStructValue

_CreateStSetter是动态创建函数

  1. using System;
  2.  
  3. using MongoDB.Configuration.Mapping.Model;
  4. using System.Collections.Generic;
  5.  
  6. namespace MongoDB.Serialization.Builders
  7. {
  8. internal class ConcreteClassMapBuilder : IObjectBuilder
  9. {
  10. private readonly IClassMap _classMap;
  11. #region Original
  12. //private readonly object _instance;
  13. #endregion
  14. #region norsd
  15. //由于struct需要装箱拆箱,_instance无法设为Null
  16. private object _instance = null;
  17. #endregion
  18. private readonly IDictionary<string, object> _extendedProperties;
  19.  
  20. public ConcreteClassMapBuilder(IClassMap classMap)
  21. {
  22. _classMap = classMap;
  23. _instance = classMap.CreateInstance();
  24.  
  25. #region norsd
  26. _bIsClass = _instance.GetType().IsClass;
  27. if (!_bIsClass)
  28. {
  29. var fields = _instance.GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
  30. foreach (var fi in fields)
  31. {
  32. SETSTVALUE setter = null;
  33. _s_dtStSetter.TryGetValue(fi, out setter);
  34. if(setter == null)
  35. {
  36. setter = _CreateStSetter(_instance.GetType(),fi);
  37. if(null == setter)
  38. continue;
  39. _s_dtStSetter.Add(fi, setter);
  40. }
  41. _dtStSetter.Add(fi.Name, setter);
  42. }
  43. }
  44. #endregion
  45.  
  46. if(!_classMap.HasExtendedProperties)
  47. return;
  48.  
  49. var extPropType = _classMap.ExtendedPropertiesMap.MemberReturnType;
  50. if (extPropType == typeof(IDictionary<string, object>))
  51. extPropType = typeof(Dictionary<string, object>);
  52. _extendedProperties = (IDictionary<string, object>)Activator.CreateInstance(extPropType);
  53. _classMap.ExtendedPropertiesMap.SetValue(_instance, _extendedProperties);
  54.  
  55. }
  56.  
  57. public void AddProperty(string name, object value)
  58. {
  59. #region Original Codes
  60. //var memberMap = _classMap.GetMemberMapFromAlias(name);
  61. //if (memberMap != null)
  62. // memberMap.SetValue(_instance, value);
  63. //else if ((!_classMap.HasDiscriminator || _classMap.DiscriminatorAlias != name) && _extendedProperties != null)
  64. // _extendedProperties.Add(name, value);
  65. #endregion
  66. #region norsd Codes
  67. if(_bIsClass)
  68. {
  69. var memberMap = _classMap.GetMemberMapFromAlias(name);
  70. if (memberMap != null)
  71. memberMap.SetValue(_instance, value);
  72. else if ((!_classMap.HasDiscriminator || _classMap.DiscriminatorAlias != name) && _extendedProperties != null)
  73. _extendedProperties.Add(name, value);
  74. }
  75. else
  76. {
  77. _SetStructValue(name, ref _instance, value);
  78. }
  79. #endregion
  80. }
  81.  
  82. public object BuildObject()
  83. {
  84. return _instance;
  85. }
  86.  
  87. public PropertyDescriptor GetPropertyDescriptor(string name)
  88. {
  89. var memberMap = _classMap.GetMemberMapFromAlias(name);
  90. if (memberMap == null)
  91. return null;
  92.  
  93. var type = memberMap.MemberReturnType;
  94. var isDictionary = false;
  95. if (memberMap is CollectionMemberMap)
  96. type = ((CollectionMemberMap)memberMap).ElementType;
  97. else if (memberMap is DictionaryMemberMap)
  98. {
  99. type = ((DictionaryMemberMap)memberMap).ValueType;
  100. isDictionary = true;
  101. }
  102.  
  103. return new PropertyDescriptor { Type = type, IsDictionary = isDictionary };
  104. }
  105.  
  106. #region norsd
  107. delegate void SETSTVALUE(ref object instance, object value);
  108. void _SetStructValue(string arg_strName , ref object arg_rInstance , object value)
  109. {
  110. SETSTVALUE setter = null;
  111. _dtStSetter.TryGetValue(arg_strName ,out setter);
  112. if (setter == null)
  113. {
  114. //throw new NotImplementedException();
  115. }
  116. else
  117. {
  118. setter(ref arg_rInstance, value);
  119. }
  120. }
  121. SETSTVALUE _CreateStSetter(Type arg_sourceType, System.Reflection.FieldInfo arg_fieldinfo)
  122. {
  123. var sourceType = arg_sourceType;
  124. var fieldInfo = arg_fieldinfo;
  125. var method2 = new System.Reflection.Emit.DynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(object).MakeByRefType(), typeof(object) }, true);
  126. var g = method2.GetILGenerator();
  127. var local = g.DeclareLocal(sourceType, true);
  128. g.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
  129. g.Emit(System.Reflection.Emit.OpCodes.Ldind_Ref);
  130. g.Emit(System.Reflection.Emit.OpCodes.Unbox_Any, sourceType);
  131. g.Emit(System.Reflection.Emit.OpCodes.Stloc_0);//将前面Load的数据Set到Local 0
  132. g.Emit(System.Reflection.Emit.OpCodes.Ldloca_S, local);
  133. g.Emit(System.Reflection.Emit.OpCodes.Ldarg_1);
  134. g.Emit(System.Reflection.Emit.OpCodes.Unbox_Any, fieldInfo.FieldType);
  135. g.Emit(System.Reflection.Emit.OpCodes.Stfld, fieldInfo);
  136. g.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
  137. g.Emit(System.Reflection.Emit.OpCodes.Ldloc_0);
  138. g.Emit(System.Reflection.Emit.OpCodes.Box, sourceType);
  139. g.Emit(System.Reflection.Emit.OpCodes.Stind_Ref);
  140. g.Emit(System.Reflection.Emit.OpCodes.Ret);
  141.  
  142. var setter = (SETSTVALUE)method2.CreateDelegate(typeof(SETSTVALUE));
  143. return setter;
  144. }
  145. bool _bIsClass = false;
  146. readonly System.Collections.Generic.Dictionary<string, SETSTVALUE> _dtStSetter = new Dictionary<string, SETSTVALUE>();
  147. //全局缓存,
  148. readonly static System.Collections.Generic.Dictionary<System.Reflection.FieldInfo, SETSTVALUE> _s_dtStSetter = new Dictionary<System.Reflection.FieldInfo, SETSTVALUE>();
  149. #endregion
  150. }
  151. }

MongoDb Samus 驱动的改进的更多相关文章

  1. Mongodb的Samus驱动

    最近开始学习Mongodb方面的东西.. 看到有很多博主都说MongoDB的第三方驱动 Samus 对Linq的支持比较好..能够降低学习的成本..所以就想从这里开始.. 但是弊端在我学习了一半的时候 ...

  2. 通过MongoDB的samus驱动实现基本数据操作

    一.MongoDB的驱动 MongoDB支持多种语言的驱动: 在此我们只介绍 C# 的驱动.仅C#驱动都有很多种,每种驱动的形式大致相同,但是细节各有千秋,因此代码不能通用.比较常用的是官方驱动和sa ...

  3. MongoDB学习笔记(二) 通过samus驱动实现基本数据操作

    传统的关系数据库一般由数据库(database).表(table).记录(record)三个层次概念组成,MongoDB是由(database).集合(collection).文档对象(documen ...

  4. MongoDB C#samus驱动

    MongoDB的c#驱动有两种,官方驱动和samus驱动,不过我更喜欢samus驱动,因为samus驱动提供了丰富的linq操作. 官方驱动:https://github.com/mongodb/mo ...

  5. Samus驱动中的Document条件

    今天要说一个东西就是Samus驱动里的 Document  和他的一个子类 Op 在Samus驱动的增删改查方法中都有这类的参数传递.. 大致的使用方法是这样.. MongoU.Find<Per ...

  6. 通过samus驱动实现基本数据操作

    传统的关系数据库一般由数据库(database).表(table).记录(record)三个层次概念组成,MongoDB是由(database).集合(collection).文档对象(documen ...

  7. (转载)MongoDB C#驱动中Query几个方法

    MongoDB C#驱动中Query几个方法 Query.All("name", "a", "b");//通过多个元素来匹配数组 Query ...

  8. 使用VS2010编译MongoDB C++驱动详解

    最近为了解决IM消息记录的高速度写入.多文档类型支持的需求,决定使用MongoDB来解决. 考虑到MongoDB对VS版本要求较高,与我现有的VS版本不兼容,在leveldb.ssdb.redis.h ...

  9. MongoDB C#驱动:

    MongoDB C#驱动: http://xiaosheng.me/2016/09/15/article24 http://www.cnblogs.com/wuhuacong/p/5098348.ht ...

随机推荐

  1. IOS开发之Iphone和Ipad应用程序图标和启动动画

    本文转载至 http://blog.csdn.net/yesjava/article/details/8782060 当我们用xcode开发iphone和ipad应用程序的时候,我们可以用一下表中所显 ...

  2. mongoose在Windows Server 2003上不能访问问题的解决

    这两天在部署EasyDarwin开源流媒体服务器到Windows Server 2003的时候,奇怪地发现,在Windows 2003上面,mongoose的web管理端口居然无法访问,但通过nets ...

  3. javascript --- 声明提前(学习笔记)

    声明提升 未声明变量 console.log(a); 在没有定义 a 的情况下,直接使用,会报错. 声明变量 console.log(a); var a = 2; 输出结果:undefined 并不会 ...

  4. 在MFC中使用大漠插件

    打开Class Wizard,Add Class...->MFC Class From TypeLib... File->Location->>> Finish-> ...

  5. PAT 天梯赛 L2-013. 红色警报 【BFS】

    题目链接 https://www.patest.cn/contests/gplt/L2-013 思路 可以通过图的连通块个数来判断 假如 一座城市的失去 改变了其他城市之间的连通性 那么 这座城市本来 ...

  6. UIView封装动画--iOS利用系统提供方法来做关键帧动画

    iOS利用系统提供方法来做关键帧动画 ios7以后才有用. /*关键帧动画 options:UIViewKeyframeAnimationOptions类型 */ [UIView animateKey ...

  7. 搭建iis本地测试服务器

    在“开始”选择 “控制面板”,默认是以“类别”显示,   改成“小图标”显示   选择“程序和功能”   进入界面后,点击“启动或关闭Windows功能”   然后勾选图中的两个选框,注意一定要显示为 ...

  8. hive和hbase本质区别——hbase本质是OLTP的nosql DB,而hive是OLAP 底层是hdfs,需从已有数据库同步数据到hdfs;hive可以用hbase中的数据,通过hive表映射到hbase表

    对于hbase当前noSql数据库的一种,最常见的应用场景就是采集的网页数据的存储,由于是key-value型数据库,可以再扩展到各种key-value应用场景,如日志信息的存储,对于内容信息不需要完 ...

  9. Pyhton:汉诺塔游戏

    #汉诺塔游戏攻略! def hanoi(n,x,y,z): if n == 1: print(x,'-->',z) else: hanoi(n-1,x,z,y) #将前n-1个盘子从x移动到y上 ...

  10. 【转载】rageagainstthecage.c源码以及注释

    如下: //头文件包含 #include <stdio.h> #include <sys/types.h> #include <sys/time.h> #inclu ...