1

我在 C# 中遇到了 System.Reflection 的一些问题。我正在从数据库中提取数据并在 JSON 字符串中检索该数据。我已经使用反射实现了将 JSON 中的数据处理到我自己声明的对象中的实现。但是,由于我通常会得到一个包含 50 - 100 个对象的数组的 JSON 字符串,因此我的程序运行速度非常慢,因为我使用反射的循环。

我听说反射很慢,但不应该这么慢。我觉得我的实现有些不对劲,因为我有一个不同的项目,我在其中使用 JSON.NET 序列化程序并用反射实例化我的对象有点不同,反射在相同的输出上运行得很好(不到一秒),而我的慢程序需要50 个对象大约需要 10 秒。

以下是我用来存储数据的课程

class DC_Host
{
    public string name;

    public void printProperties()
    {
        //Prints all properties of a class usign reflection
        //Doesn't really matter, since I'm not usign this for processing
    }
}

class Host : DC_Host
{
    public string asset_tag;
    public string assigned;
    public string assigned_to;
    public string attributes;
    public bool? can_print;
    public string category;
    public bool? cd_rom;
    public int? cd_speed;
    public string change_control;
    public string chassis_type;
    //And some more properties (around 70 - 80 fields in total)

您将在下面找到我将信息处理为存储在列表中的对象的方法。JSON 数据存储在一个字典中,该字典包含另一个字典,用于在 JSON 输入中定义的每个数组对象。反序列化 JSON 会在几毫秒内发生,所以那里不应该有问题。

public List<DC_Host> readJSONTtoHost(ref Dictionary<string, dynamic> json)
{
    bool array = isContainer();

    List<DC_Host> hosts = new List<DC_Host>();

    //Do different processing on objects depending on table type (array/single)
    if (array)
    {
        foreach (Dictionary<string, dynamic> obj in json[json.First().Key])
        {
            hosts.Add(reflectToObject(obj));
        }
    }
    else
    {
        hosts.Add(reflectToObject(json[json.First().Key]));
    }

    return hosts;
}

private DC_Host reflectToObject(Dictionary<string,dynamic> obj)
{
    Host h = new Host();

    FieldInfo[] fields = h.GetType().GetFields();

    foreach (FieldInfo f in fields)
    {
        Object value = null;

        /* IF there are values that are not in the dictionairy or where wrong conversion is
         * utilised the values will not be processed and therefore not inserted into the 
         * host object or just ignored. On a later stage I might post specific error messages
         * in the Catch module. */

        /* TODO : Optimize and find out why this is soo slow */
        try
        {
            value = obj[convTable[f.Name]];
        }
        catch { }

        if (value == null)
        {
            f.SetValue(h, null);
            continue;
        }
        // Het systeem werkt met list containers, MAAAR dan mogen er geen losse values zijn dus dit hangt
        // zeer sterk af van de implementatie van Service Now.
        if (f.FieldType == typeof(List<int?>)) //Arrays voor strings,ints en bools dus nog definieren 
        {
            int count = obj[convTable[f.Name]].Count;
            List<int?> temp = new List<int?>();
            for (int i = 0; i < count; i++)
            {
                temp.Add(obj[convTable[f.Name]][i]);
                f.SetValue(h, temp);
            }
        }
        else if (f.FieldType == typeof(int?))
            f.SetValue(h, int.Parse((string)value));
        else if (f.FieldType == typeof(bool?))
            f.SetValue(h, bool.Parse((string)value));
        else
            f.SetValue(h, (string)value);
    }

    Console.WriteLine("Processed " + h.name);

    return h;
}

我不确定 JSON.NET 在后台使用反射的实现是什么,但我假设他们使用我缺少的东西来优化他们的反射。

4

2 回答 2

3

基本上,像这样的高性能代码倾向于广泛使用元编程;很多ILGenerator等等(或者Expression/CodeDom如果你觉得这很可怕)。PetaPoco 今天早些时候展示了一个类似的例子:防止 DynamicMethod VerificationException - 操作可能会破坏运行时

您还可以查看其他序列化引擎的代码,例如 protobuf-net,它具有大量的元编程。

如果你不想走那么远,你可以看看FastMember,它为你处理疯狂的事情,所以你只需要担心对象/成员名称/值。

于 2012-07-27T08:02:35.113 回答
2

对于遇到这篇文章的人,我将在这里发布我对我的问题的解决方案。这个问题与反思无关。有一些方法可以使用反射来提高速度,比如 CodesInChaos 和 Marc Gravell 提到,Marc 甚至为没有太多低级反射经验的人创建了一个非常有用的库(FastMember)。

然而,解决方案与反射本身无关。我有一个 Try Catch 语句来评估我的字典中是否存在值。使用 try catch 语句来处理程序流不是一个好主意。处理异常对性能很重要,尤其是在运行调试器时,Try Catch 语句会严重影响性能。

//New implementation, use TryGetValue from Dictionary to check for excising values.
dynamic value = null;
obj.TryGetValue(convTable[f.Name], out value);

由于我省略了 TryCatch 语句,我的程序现在运行得非常好。

于 2012-07-27T08:13:41.050 回答