使用反射来序列化文件 [英] Using reflection to serialize files

查看:35
本文介绍了使用反射来序列化文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我公司的应用程序中,有一个查看器可以接收一条消息并从中创建一个 XML 文档,以便向客户展示它.每条消息都有自己的类,到目前为止必须单独编写,如下面的示例所示.类名在m_msgTypeVersion"中给出,所以我认为应该可以使用反射来概括这个 switch 语句中的情况,这样当新的消息类型添加到应用程序时就不必更新了.

但是,我在执行此操作时遇到了一些麻烦.我不知道如何转换为特定类型.我使用的是 .NET 3.5,所以 dynamic 关键字不存在.但是我需要将实例转换为特定的类而不是 Object.

以及如何使用序列化程序?它说它需要一个 T.但我的类型不适合这个.它给出了一个语法错误.

 开关 (m_msgTypeVersion){默认:throw new NotImplementedException("消息类型" + m_msgTypeVersion + " 未实现到 XmlElement 的转换!");案例UTILMD_D11AUN51":UTILMD_D11AUN51 utilmd51 = 新的 UTILMD_D11AUN51();串行器serUtilmd51 = 新序列化器();if (serUtilmd51.Deserialize(m_ediMsg, out utilmd51, out ex))xml = new XmlDocument().ReadNode(serUtilmd51.Serialize(utilmd51, "").Root.CreateReader()) 作为 XmlElement;休息;案例UTILMD_D11AUN51a":UTILMD_D11AUN51a utilmd51a = 新 UTILMD_D11AUN51a();串行器serUtilmd51a = 新序列化器();if (serUtilmd51a.Deserialize(m_ediMsg, out utilmd51a, out ex))xml = new XmlDocument().ReadNode(serUtilmd51a.Serialize(utilmd51a, "").Root.CreateReader()) 作为 XmlElement;休息;案件 ...

}

返回xml;

我的尝试....

Type type = Type.GetType("m_msgTypeVersion");Object myObject = Activator.CreateInstance(type);//不需要对象,而是转换为特定类型序列化器<类型>serUtilmd51 = 新的序列化器<类型>();//不适用于类型"

解决方案

基本上,你在这里有三个选择(在没有动态的情况下);在反射中做所有事情,进行核心元编程,或使用单个反射黑客跳入通用方法.后者可能是您最好的选择,因此:

第 1 步:创建一个可以执行您想要的操作的通用方法:

public static void EvilHack(...args...){T myObject = Activator.CreateInstance();串行器serUtilmd51 = 新的序列化器();//等等}

第 2 步:通过反射为未知类型调用该方法

Type type = Type.GetType("m_msgTypeVersion");typeof(YourEnclosureType).GetMethod("EvilHack").MakeGenericMethod(type).Invoke(null, args);

请注意,您可以添加返回类型等并从 .Invoke 中捕获返回值..Invoke 调用中的前导 null 是实例 - 在这种情况下 null 因为它是一个 static 方法;如果您使方法非静态,请将其替换为目标实例.如果您将方法设为非public,则需要在 GetMethod 调用中指定 BindingFlags.

完整工作示例:

使用系统;类 YourEnclosureType{静态无效主(){Type type = Type.GetType("m_msgTypeVersion");对象[] args = null;//没有参数typeof(YourEnclosureType).GetMethod("EvilHack").MakeGenericMethod(type).Invoke(null, args);}public static void EvilHack(){T myObject = Activator.CreateInstance();串行器serUtilmd51 = 新的序列化器();serUtilmd51.DoIt(myObject);}}class m_msgTypeVersion//最糟糕的.名称.曾经{ }类序列化器{公共无效DoIt(T obj){Console.WriteLine("我正在序列化" + obj);}}

In my company's application, there's a viewer that will take a message and create an XML document out of it so it can be presented nicely for the customers. Each message has their own class and so far must individually be written like in the examle below. The class name is given in the "m_msgTypeVersion", so I figured it should be possible to use reflection to generalize the cases in this switch statement so it doesn't have to be updated when new message types are added to the application.

However, I am having a bit of trouble doing this. I don't know how to cast to the specific type. I am using .NET 3.5, so the dynamic keyword isn't there. But I need to cast the instance to the specific class instead of Object.

And how to use the Serializer? It says it needs a T. But my type doesn't work with this. It gives a syntax error.

switch (m_msgTypeVersion)
{
    default:
        throw new NotImplementedException("Message type " + m_msgTypeVersion + " conversion to XmlElement not implemented!");
    case "UTILMD_D11AUN51":
        UTILMD_D11AUN51 utilmd51 = new UTILMD_D11AUN51();
        Serializer<UTILMD_D11AUN51> serUtilmd51 = new Serializer<UTILMD_D11AUN51>();
        if (serUtilmd51.Deserialize(m_ediMsg, out utilmd51, out ex))
            xml = new XmlDocument().ReadNode(serUtilmd51.Serialize(utilmd51, "").Root.CreateReader()) as XmlElement;
        break;
    case "UTILMD_D11AUN51a":
        UTILMD_D11AUN51a utilmd51a = new UTILMD_D11AUN51a();
        Serializer<UTILMD_D11AUN51a> serUtilmd51a = new Serializer<UTILMD_D11AUN51a>();
        if (serUtilmd51a.Deserialize(m_ediMsg, out utilmd51a, out ex))
            xml = new XmlDocument().ReadNode(serUtilmd51a.Serialize(utilmd51a, "").Root.CreateReader()) as XmlElement;
        break;
    case ...

}

return xml;

My attempt....

Type type = Type.GetType("m_msgTypeVersion");
Object myObject = Activator.CreateInstance(type); // need not object, but cast to specific type
Serializer<type> serUtilmd51 = new Serializer<type>(); // does not work with "type"

解决方案

Basically, you've got three choices here (in the absence of dynamic); do everything in reflection, do hardcore meta-programming, or use a single reflection hack to jump into a generic method. The latter is probably your best option, so:

Step 1: create a generic method that does what you want:

public static void EvilHack<T>(...args...)
{
     T myObject = Activator.CreateInstance<T>();
     Serializer<T> serUtilmd51 = new Serializer<T>();
     // etc
}

Step 2: call that method for the unknown type via reflection

Type type = Type.GetType("m_msgTypeVersion");
typeof(YourEnclosingType).GetMethod("EvilHack").MakeGenericMethod(type)
            .Invoke(null, args);

Note you can add a return type etc and catch the return value from .Invoke. The leading null in the .Invoke call is the instance - null in this case because it is a static method; replace that with the target instance if you make the method non-static. If you make the method non-public, you'll need to specify BindingFlags in the GetMethod call.

Fully working example:

using System;

class YourEnclosingType
{
    static void Main()
    {
        Type type = Type.GetType("m_msgTypeVersion");
        object[] args = null; // no args
        typeof(YourEnclosingType).GetMethod("EvilHack").MakeGenericMethod(type)
                    .Invoke(null, args);
    }
    public static void EvilHack<T>()
    {
        T myObject = Activator.CreateInstance<T>();
        Serializer<T> serUtilmd51 = new Serializer<T>();
        serUtilmd51.DoIt(myObject);
    }
}
class m_msgTypeVersion // worst. name. ever
{ }
class Serializer<T>
{
    public void DoIt(T obj)
    {
        Console.WriteLine("I'm serializing " + obj);
    }
}

这篇关于使用反射来序列化文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆