日期:2014-05-16 浏览次数:20415 次
一直使用 MongoDb 的 Samus C#驱动。
其有一个缺陷,就是无法支持struct的读写。
但是一般数据都用Class包装,所以也没有太在意。
随着这些天尝试写入 KLineData 时,遇到了非常龌龊的问题。
KLineData这个Class内部有一个TICK[4] 这样一个数组,TICK是一个结构类型
Samus可以顺利的写入KLineData
但是读取时,立刻发生了异常。
查看内部实现,发现其用Emit做的ORM,代码如下:
1.创建Map
private ExtendedPropertiesMap CreateExtendedPropertiesMap(Type classType){
var extPropMember = _profile.FindExtendedPropertiesMember(classType);
if(extPropMember == null)
return null;
return new ExtendedPropertiesMap(
extPropMember.Name,
extPropMember.GetReturnType(),
MemberReflectionOptimizer.GetGetter(extPropMember),
MemberReflectionOptimizer.GetSetter(extPropMember));
}其中GetSetter代码如下
public static Action<object, object> GetSetter(MemberInfo memberInfo)
{
if(memberInfo == null)
throw new ArgumentNullException("memberInfo");
if(memberInfo.MemberType != MemberTypes.Field && memberInfo.MemberType != MemberTypes.Property)
throw new ArgumentException("Only fields and properties are supported.", "memberInfo");
if(memberInfo.MemberType == MemberTypes.Field)
return GetFieldSetter(memberInfo as FieldInfo);
if(memberInfo.MemberType == MemberTypes.Property)
return GetPropertySetter(memberInfo as PropertyInfo);
throw new InvalidOperationException("Can only create setters for fields or properties.");
}
public static Action<object, object> GetFieldSetter(FieldInfo fieldInfo)
{
if(fieldInfo == null)
throw new ArgumentNullException("fieldInfo");
var key = CreateKey(fieldInfo);
Action<object, object> setter;
lock (SyncObject)
{
if (SetterCache.TryGetValue(key, out setter))
return setter;
}
if (fieldInfo.IsInitOnly || fieldInfo.IsLiteral)
throw new InvalidOperationException("Cannot create a setter for a readonly field.");
var sourceType = fieldInfo.DeclaringType;
var method = new DynamicMethod("Set" + fieldInfo.Name, null, new[] {typeof (object), typeof (object)}, true);
var gen = method.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Castclass, sourceType);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
gen.Emit(OpCodes.Stfld, fieldInfo);
gen.Emit(OpCodes.Ret);
setter = (Action<object, object>) method.CreateDelegate(typeof (Action<object, object>));
lock (SyncObject)
{
SetterCache[key] = setter;
}
return setter;
} gen.Emit(OpCodes.Ldarg_0); // 把参数0入栈