【问题标题】:Serialize type object to concrete type dynamically动态地将类型对象序列化为具体类型
【发布时间】:2014-08-17 15:23:46
【问题描述】:

您好,我很难解决以下问题。

我提供了两个参数

  • 动态对象 (obj)(包含具有值的属性)
  • 一个字符串 (typeName)(包含一个类型名称,可以是任何与一系列具体定义的类型相匹配的名称)。

请注意,obj 是动态的,因此我没有任何设计时访问其任何类型或属性的权限。

据此,我需要将此匿名对象转换为其具体类型,并使用对象中包含的值对其进行初始化并序列化。

我现在拥有的是这样的:

    public class ExampleObj
    {
        public int A { get; set; }
        public string B { get; set; }
    }

    static void Main(string[] args)
    {
        var typeName = "ExampleObj";

        object obj = new
        {
            A = 5,
            B = "xx"
        };

        Type type = Type.GetType(typeName);

        var serialiser = new XmlSerializer(type);
        var sb = new StringBuilder();

        serialiser.Serialize(new StringWriter(sb), obj);
    }

由于明显的原因,最后一行失败(运行时现在知道如何从类型对象转换为具体类型 ExampleObj,这就是我卡住的地方。

我还考虑过 Activator.CreateInstance 来动态创建一个实例,但我的知识和搜索并没有表明我如何在序列化之前用正确的值初始化这个实例。

【问题讨论】:

标签: c# serialization dynamic reflection types


【解决方案1】:

请考虑下一个示例(对于类型名,您需要提供包含该类型的命名空间):

var typeName = "YourNamespace.ExampleObj";

object obj = new
{
    A = 5,
    B = "xx"
};

var props = TypeDescriptor.GetProperties(obj);
Type type = Type.GetType(typeName);
ExampleObj instance = (ExampleObj)Activator.CreateInstance(type);
instance.A = (int)props["A"].GetValue(obj);
instance.B = (string)props["B"].GetValue(obj);

//serialize the instance now...

如果 obj 是 var obj 那么:

var obj = new
{
    A = 5,
    B = "xx"
};

Type type = Type.GetType(typeName);
ExampleObj instance = (ExampleObj)Activator.CreateInstance(type);
instance.A = obj.A;
instance.B = obj.B;

【讨论】:

  • 你错过了 obj 是动态的,所以我没有编译时间访问 ExampleObj 类型或 A 和 B 属性
【解决方案2】:

这是我在控制器方法中的最终解决方案,该方法通过使用动态类型按要求工作。我最初的问题的关键概念是你不能(形成我可以收集的)自动进行演员表。您需要某种切换逻辑,根据您想要支持的类型进行手动转换(或使用问题中 cmets 部分中建议的第三方工具)

    [HttpPost]
    public ActionResult SaveRule(int? id, ExpandoObject ruleObj, string ruleTypeName)
    {
        Type type = GetTypeFromName(ruleTypeName);
        var instance = Activator.CreateInstance(type);

        foreach (var prop in type.GetProperties())
        {
            object val;
            ((IDictionary<string, object>)ruleObj).TryGetValue(prop.Name, out val);

            val = AutoMapObjectType(prop, val);

            prop.SetValue(instance, val);
        }

        var serialiser = new XmlSerializer(type);
        var sb = new StringBuilder();
        serialiser.Serialize(new StringWriter(sb), instance);

        if (id != null)
        {
            RuleDataAccess.SaveRule((int)id, sb.ToString()); 
        }

        return new JsonResult();
    }

    public static object AutoMapObjectType(PropertyInfo prop, object val)
    {

        if (prop.PropertyType.BaseType.Name == "Enum")
        {
            return Enum.Parse(prop.PropertyType, val.ToString());
        }
        else
        {
            switch (prop.PropertyType.Name)
            {
                case "Boolean":
                    return Convert.ToBoolean(short.Parse(val.ToString()));
                case "String":
                case "Int32":
                case "Decimal":
                    return Convert.ChangeType(val, prop.PropertyType);
                default:
                    return Convert.ChangeType(val, prop.PropertyType); //Attempt to convert with implicit casting/conversion, (will fail if explicit cases are not handled)
            }
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-19
    • 2019-11-22
    相关资源
    最近更新 更多