none
如何给动态(匿名)类实现索引赋值,且不使用idic接口

    问题

  • e.g. 

    var a = new { a=1,b="2" };

    return Json(a) 

    jsoutput : { a=1,b="2" }

    如果 属性名本身是变量怎么办

    我想要下面这个东西

    var a = new X();

    a["a"] = 1;

    a["b"] = "2";

    return Json(a); 

    jsoutput:{a=1,b="2"}

    //注

    有一点基础知识

    匿名类的实现 基础 匿名类有一个参数构造 和各个属性的get实现, 应该是不提供set实现的

    并且匿名类做了类型优化 , var a = { a = 1,b="2"} 和 var b={s=1,y="2"} 其实是一个内部的类型 记作<>f_axxxx0<int,string>

    a b s y 类似一个 真实属性的引用而已

    曾尝试使用 TypeBuilder 做动态类型 实现了索引器 但是 并没有实现 类型结构存储的优化

    public class AnonymousFactory
        {
            private string name;
            private object _result;
            private static AssemblyBuilder dynamicAssembly;
            private static ModuleBuilder dynamicModule;
            private TypeBuilder dynamicType;
            //类型池 可以改造
            private static Dictionary<string, Type> typepool = new Dictionary<string, Type>();
            public AnonymousFactory(string name)
            {
                this.name = name;
                if(dynamicAssembly==null)
                    dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("MyDynamicAssembly"), AssemblyBuilderAccess.Run);
                if(dynamicModule==null)
                    dynamicModule = dynamicAssembly.DefineDynamicModule("MyDynamicAssemblyModule");
                if(!typepool.Keys.Contains(name))
                    dynamicType = dynamicModule.DefineType(name, TypeAttributes.Public);
            }
            public AnonymousFactory()
            {
                this.name = Guid.NewGuid().ToString();
                if (dynamicAssembly == null)
                    dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("MyDynamicAssembly"), AssemblyBuilderAccess.Run);
                if (dynamicModule == null)
                    dynamicModule = dynamicAssembly.DefineDynamicModule("MyDynamicAssemblyModule");
                if (!typepool.Keys.Contains(name))
                    dynamicType = dynamicModule.DefineType(name, TypeAttributes.Public);
            }
            private Dictionary<string, object> _values = new Dictionary<string, object>();
    
            //属性赋值索引器
            public object this[string propertyName]
            {
                set
                {
                    if (_result == null)
                    {
                        if (_values.ContainsKey(propertyName) == true)
                        {
                            _values[propertyName] = value;
                        }
                        else
                        {
                            _values.Add(propertyName, value);
                        }
                    }
                    else
                    {
                        _result.GetType().GetProperty(propertyName).SetValue(_result, value, null);
                    }
                }
                get
                {
                    if (_result == null)
                    {
                        if (_values.ContainsKey(propertyName) == true)
                        {
                            return _values[propertyName];
                        }
                        return null;
                    }
                    else
                    {
                        return _result.GetType().GetProperty(propertyName).GetValue(_result, null);
                    }
                }
            }
            //生成动态类型的方法
            public object GetAnonymous()
            {
                if (!typepool.Keys.Contains(name))
                {
                    if (_values.Keys == null || _values.Keys.Count == 0)
                        return null;
                    var fields = new List<FieldBuilder>();
                    var types = new List<Type>();
                    foreach (var item in _values)
                    {
                        var type = item.Value.GetType();
                        //添加属性
                        fields.Add(AddProperty(dynamicType, item.Key, type));
                        types.Add(type);
                    }
                    //添加构造
                    AddConstructor(dynamicType, fields.ToArray(), types.ToArray());
                    //生成类型 
                    Type myType = dynamicType.CreateType();
                    //此处以类名和 Type 存储
                    //可以优化成 按参数数组的类型名存储 
                    //e.g.  3参数 (object_object_object_)
                    //      2参数 (object_object_)
                    //      类型优化(int_string_)
                    typepool.Add(name, myType);
                }
                _result = Activator.CreateInstance(typepool[name]);
                foreach (var item in _result.GetType().GetProperties())
                {
                    item.SetValue(_result, _values[item.Name], null);
                }
                return _result;
            }
            //类型增加属性
            private static FieldBuilder AddProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
            {
                const MethodAttributes getSetAttr = MethodAttributes.Public;
    
                FieldBuilder field = typeBuilder.DefineField(propertyName, typeof(string), FieldAttributes.Private);
                PropertyBuilder property = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType,
                    new[] { propertyType });
    
                MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_value", getSetAttr, propertyType,
                    Type.EmptyTypes);
                ILGenerator getIl = getMethodBuilder.GetILGenerator();
                getIl.Emit(OpCodes.Ldarg_0);
                getIl.Emit(OpCodes.Ldfld, field);
                getIl.Emit(OpCodes.Ret);
    
                MethodBuilder setMethodBuilder = typeBuilder.DefineMethod("set_value", getSetAttr, null,
                    new[] { propertyType });
                ILGenerator setIl = setMethodBuilder.GetILGenerator();
                setIl.Emit(OpCodes.Ldarg_0);
                setIl.Emit(OpCodes.Ldarg_1);
                setIl.Emit(OpCodes.Stfld, field);
                setIl.Emit(OpCodes.Ret);
    
                property.SetGetMethod(getMethodBuilder);
                property.SetSetMethod(setMethodBuilder);
                return field;
            }
            //类型增加构造函数
            private static void AddConstructor(TypeBuilder typeBuilder, FieldBuilder[] field, params Type[] types)
            {
                ConstructorBuilder ivCtorbase = typeBuilder.DefineConstructor(
                          MethodAttributes.Public,
                          CallingConventions.HasThis, null
                          );
                ILGenerator ctorILbase = ivCtorbase.GetILGenerator();
                Type objTypebase = Type.GetType("System.Object");
                ConstructorInfo objCtorbase = objTypebase.GetConstructor(new Type[0]);
                ctorILbase.Emit(OpCodes.Ldarg_0);
                ctorILbase.Emit(OpCodes.Call, objCtorbase);
                ctorILbase.Emit(OpCodes.Ret);
    
                ConstructorBuilder ivCtor = typeBuilder.DefineConstructor(
                          MethodAttributes.Public,
                          CallingConventions.HasThis,
                          types);
                ILGenerator ctorIL = ivCtor.GetILGenerator();
                Type objType = Type.GetType("System.Object");
                ConstructorInfo objCtor = objType.GetConstructor(new Type[0]);
                ctorIL.Emit(OpCodes.Ldarg_0);
                ctorIL.Emit(OpCodes.Call, objCtor);
                var i = 0;
                foreach (var item in field)
                {
                    ctorIL.Emit(OpCodes.Ldarg_0);
                    i++;
                    if (i == 1)
                    {
                        ctorIL.Emit(OpCodes.Ldarg_1);
                    }
                    else if (i == 2)
                    {
                        ctorIL.Emit(OpCodes.Ldarg_2);
                    }
                    else if (i == 3)
                    {
                        ctorIL.Emit(OpCodes.Ldarg_3);
                    }
                    else
                    {
                        ctorIL.Emit(OpCodes.Ldarg_S);
                    }
                    ctorIL.Emit(OpCodes.Stfld, item);
                }
                ctorIL.Emit(OpCodes.Ret);
            }
        }

    使用的话 AnonymousFactory a = new AnonymousFactory();

    a["a"] = 1;

    a["b"] = "s";

    var b = a.GetAnonymous();

    a["a"] = 2;

    a["b"] = "e";

    b的属性值会被修改


    研小艾

    2016年3月1日 6:31

答案

  • 你好 研小艾,

    从匿名类型的定义来看,“匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型类型名由编译器生成,并且不能在源代码级使用每个属性的类型由编译器推断”。具体定义看这里, https://msdn.microsoft.com/zh-cn/library/bb397696.aspx

    结合你描述的情况来看,你想在编程时候从代码层面来修改一些属性,这场景本身就和匿名类型的定义冲突了,所以我觉得是不是应该考虑一下使用其他的类型或者自己定义一个类型来完成需求呢?

    看你的代码,感觉像是在runtime的时候需要动态定义类型吗?请看一下动态源代码生成和编译, https://msdn.microsoft.com/zh-cn/library/650ax5cx(v=vs.110).aspx 我觉得可能更适合你的场景。


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.



    2016年3月3日 2:46

全部回复

  • 怎么没问 回复一下。。。。

    这不是demo

    这是一个问题

    有没有人 研究过匿名类型的 内部实现


    研小艾

    2016年3月1日 7:34
  • 你好 研小艾,

    从匿名类型的定义来看,“匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型类型名由编译器生成,并且不能在源代码级使用每个属性的类型由编译器推断”。具体定义看这里, https://msdn.microsoft.com/zh-cn/library/bb397696.aspx

    结合你描述的情况来看,你想在编程时候从代码层面来修改一些属性,这场景本身就和匿名类型的定义冲突了,所以我觉得是不是应该考虑一下使用其他的类型或者自己定义一个类型来完成需求呢?

    看你的代码,感觉像是在runtime的时候需要动态定义类型吗?请看一下动态源代码生成和编译, https://msdn.microsoft.com/zh-cn/library/650ax5cx(v=vs.110).aspx 我觉得可能更适合你的场景。


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.



    2016年3月3日 2:46