首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用DynamicObject存储类型信息

用DynamicObject存储类型信息
EN

Stack Overflow用户
提问于 2014-11-03 22:30:09
回答 2查看 546关注 0票数 2

我试图设计一个进行提取、转换、加载操作的过程。我希望使用管道中的ExpandoObject,以便轻松地将列添加到数据流中。基本上,我从某种数据源读取数据,将其转换为动态数据,并将其返回到一条转换管道,该管道根据现有属性或其他属性向其添加属性,然后将其流到数据库中。

我遇到的问题是,即使我添加了一个Nullable类型,我也需要向扩张型对象添加的所有属性的类型信息。如果由于该值的装箱而使Nullable类型为null,则会丢失此值。我需要类型信息,这样在管道的末尾,我就可以在ExpandoObjects枚举上实现一个数据存储器,并将数据流到数据库中。

我曾希望SetMemberBinder.ReturnType属性可以帮助我,但它似乎返回了一个对象。

下面是一些示例代码:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Dynamic;

using Xunit

namespace Whanger
{
    public class MyExpando : DynamicObject
    {
        Dictionary<string, object> properties = new Dictionary<string, object>();
        Dictionary<string, Type> propertyTypes = new Dictionary<string, Type>();

        public Dictionary<string, Type> Types
        {
            get
            {
                return propertyTypes;
            }
        }

        public Dictionary<string, object> Values
        {
            get
            {
                return properties;
            }
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (properties.ContainsKey(binder.Name))
            {
                result = properties[binder.Name];
                return true;
            }
            else
            {
                result = null;
                return false;
            }
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            properties[binder.Name] = value;
            propertyTypes[binder.Name] = binder.ReturnType;//always object :(
            return true;
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            dynamic method = properties[binder.Name];
            result = method(args[0].ToString(), args[1].ToString());
            return true;
        }
    }

    public class MyExpandoTests
    {
        [Fact]
        public void CanAddDynamicMembers()
        {
            dynamic obj = new MyExpando();
            obj.Name = "Wibble";
            obj.Value = 2;

            Assert.Equal(obj.Name, "Wibble");
            Assert.Equal(obj.Value, 2);
        }

        [Fact]
        public void CanMaintainType()
        {
            dynamic obj = new MyExpando();
            int? nullableInt = null;
            obj.NullInt = nullableInt;
            obj.Name = "Wibble";
            Assert.Equal(obj.Name, "Wibble");
            Assert.Null(obj.NullInt);
            //fails
            Assert.Equal(typeof(int?), ((MyExpando)obj).Types["NullInt"]);


        }
    }
}

有办法从TrySetMember中找出类型吗?我想知道是否有什么方法可以使用某种表达树魔法的东西?

如果有人有什么好主意的话,我很想听听。除了可空类型之外,所有这些操作都很好,但是对于数据库操作来说,它们是关键。

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-03 23:50:28

是的,这是可能的。

我对类型信息是否存储在某个地方做了一些研究,并发现在设置成员的过程中使用了一个Func<System.Runtime.CompilerServices.CallSite,object,int?,object>对象。这可能用于存储绑定以供以后使用。

但是,这个缓存实际上是传递给绑定器:私有CallSiteBinder.Cache字段的。它包含一个IDictionary<Type,object>,它包含作为键的缓存委托的类型和委托本身。因此,通过检查委托类型的泛型参数,可以获得赋值中使用的表达式的类型。

完整方法:

代码语言:javascript
复制
private static readonly FieldInfo CallSiteBinder_Cache = typeof(CallSiteBinder).GetField("Cache", BindingFlags.NonPublic | BindingFlags.Instance);
private static Type BindingType(CallSiteBinder binder)
{
    IDictionary<Type,object> cache = (IDictionary<Type,object>)CallSiteBinder_Cache.GetValue(binder);
    Type ftype = cache.Select(t => t.Key).FirstOrDefault(t => t != null && t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Func<,,,>));
    if(ftype == null) return null;
    Type[] genargs = ftype.GetGenericArguments();
    return genargs[2];
}

该方法获取秘密缓存字典,并从Func<T1,T2,T3,TResult>中找到一个已构造的类型密钥。然后只提取类型参数。

票数 0
EN

Stack Overflow用户

发布于 2014-11-03 22:51:52

你就不能加个过载吗

代码语言:javascript
复制
public override bool TrySetMember<T>(SetMemberBinder binder, Nullable<T> value)
{
    properties[binder.Name] = value;
    propertyTypes[binder.Name] = typeof(Nullable<T>);
    return true;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26724479

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档