从Dictionary <string,object>初始化类型为T的对象

AC.*_*AC. 8 c# reflection serialization json

我正在寻找更通用/"标准"的方式来从一组对字符串,对象实例化某种类型T的对象.对我来说,看起来应该有一些众所周知的方法,但我找不到它,所以我想出了这段代码.有人知道更好的事吗?

// usage
public class test
    {
    public int field1;
    public string field2;
    public bool field3;
    public string[] field4;
    public IDictionary<string,object> field5 { get; set; }

    public static IDictionary<string,object> dynamic()
        {
        return new Dictionary<string,object>{
            { "field1", 2 },
            { "field2", "string" },
            { "field3", true },
            { "field4", new[] { "id3", "id4", "id5" } },
            { "field5", new Dictionary<string,object>{ { "id1", "" } } }
            };
        }
    }

...
var r = new dynamic_data_serializer<test>().create( test.dynamic() );
...

// 
public class dynamic_data_serializer< T >
    {
    public T create( object obj )
        {
        var result = default(T);
        if ( obj == null )
            return result;

        var ttype = typeof(T);
        var objtype = obj.GetType();
        if ( ttype.IsAssignableFrom( objtype ) ) {
            result = (T)obj;
            return result;
            }

        if ( ttype.IsClass ) { // custom classes, array, dictionary, etc.
            result = Activator.CreateInstance<T>();

            if ( objtype == typeof(IDictionary<string,object>) || 
                    objtype == typeof(Dictionary<string,object>) ) {
                var obj_as_dict = obj as IDictionary<string,object>; 
                var fields = ttype.GetFields();
                if ( fields.Length > 0 )
                    set_fields_from( result, fields, obj_as_dict );

                var properties = ttype.GetProperties();
                if ( properties.Length > 0 )
                    set_properties_from( result, properties, obj_as_dict );
                }
            }    
        return result;
        }

    private void set_fields_from( T _this_, FieldInfo[] fields, IDictionary<string,object> obj ) {
        foreach ( var fld in fields ) {
            var v = find( obj, fld.Name );
            if ( v != null ) {
                var mobj = call_deserialize( fld.FieldType, v );
                fld.SetValue( _this_, mobj );
                }
            }
        }

    private void set_properties_from( T _this_, PropertyInfo[] properties, IDictionary<string,object> obj ) {
        foreach ( var prop in properties ) {
            var v = find( obj, prop.Name );
            if ( v != null ) {
                var mobj = call_deserialize( prop.PropertyType, v );
                prop.SetValue( _this_, mobj, null );
                }
            }
        }

    private object find( IDictionary<string,object> obj, string name ) {
        foreach ( var kv in obj )
            if ( string.Compare( kv.Key, name, true ) == 0 )
                return kv.Value;
        return null;
        }

    private object call_deserialize( Type des_type, object value ) {
        var gtype = typeof(dynamic_data_serializer<>);
        Type desz_type = gtype.MakeGenericType( new[]{ des_type } );
        object desz = Activator.CreateInstance( desz_type );
        var method_type = desz_type.GetMethod( "create" ); 
        return method_type.Invoke( desz, new[]{ value } );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Gab*_*abe 2

DataContractJsonSerializer 太慢,但您正在使用反射?如果您必须反序列化大量对象,我建议使用编译的 lambda 而不是反射。lambda 只能设置属性,不能设置字段(至少在 .Net 3.5 中),因此您可能必须调整使用它的类,但这是值得的,因为它的速度快了 1000 倍。

下面是一个函数,它创建一个属性设置器,给定类型和PropertyInfo要设置的属性:

    static Action<object, TValue> MakeSetter<TValue>(Type tclass, PropertyInfo propInfo)
    {
        var t = lambda.Expression.Parameter(typeof(object), "t");
        var v = lambda.Expression.Parameter(typeof(TValue), "v");
        // return (t, v) => ((tclass)t).prop = (tproperty)v
        return (Action<object, TValue>)
            lambda.Expression.Lambda(
                lambda.Expression.Call(
                    lambda.Expression.Convert(t, tclass),
                    propInfo.GetSetMethod(),
                    lambda.Expression.Convert(v, propInfo.PropertyType)),
                t,
                v)
            .Compile();
    }
Run Code Online (Sandbox Code Playgroud)

您将为每个类都有一个 setter 字典,每当您必须设置类的属性时,您都会在字典中查找该属性的 setter 并使用要分配的值来调用它,如下所示:setters[propName](_this_, value);