1

C# の System.Reflection に問題があります。データベースからデータを取得し、そのデータを JSON 文字列で取得しています。リフレクションを使用して、JSON から自己宣言されたオブジェクトにデータを処理する独自の実装を作成しました。ただし、通常は 50 ~ 100 個のオブジェクトの配列を持つ JSON 文字列を取得するため、リフレクションで使用しているループのために、プログラムの実行が非常に遅くなります。

反映が遅いと聞いたことがありますが、それほど遅くはないはずです。JSON.NET シリアライザーを使用する別のプロジェクトがあり、同じ出力 (1 秒未満) で問題なく実行されるリフレクションを使用してオブジェクトを少し異なる方法でインスタンス化する別のプロジェクトがあるため、実装に何か問題があると感じています。 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 は同様の例を示しました

また、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 に答える