0

データクラスのインスタンスをデータベースに保存し、データベースからロードしたいと考えています。そして、SQLコマンドを自動的に生成したい。だから、それを解決するために Dictionary< string, string> を使う必要があると思います。

私の古い質問を参照してください: 2D 文字列配列を 2D [int, double, bool, ..] 配列に変換する方法は?

このような作業工程。

  1. data-class インスタンスをディクショナリ < string, string> に変換します。
  2. txt、データベースなどとの間で辞書を保存/ロードします。
  3. 辞書をデータクラスのインスタンスに変換する

とにかく問題を解決したと思います。しかし、2D 配列メソッドの変換はまだ完璧ではないと思います。FieldInfo.SetValue 関数を呼び出すときに、私のソリューションのようにスイッチ/ケース状態を使用せずに型変換を解決する別の方法があるのだろうか。

コードを簡素化するのに役立ちます。

このようなデータクラス

        public class DCylinderData
    {
        public int ID;

        public int[] Solenoid = new int[2];
        public int[] UpSensor = new int[DEF_MAX_CYLINDER_SENSOR];
        public int[] DownSensor = new int[DEF_MAX_CYLINDER_SENSOR];

        public double MovingTime;

        public ECylinderType CylinderType;
        public ESolenoidType SolenoidType;

        public bool[] boolTest = new bool[3];
        public string[] nameTest = new string[2];
        public int[,] TwoDimension = new int[3,4];

        public DCylinderData()
        {
        }
    }

このようなメインコード

            // 0. initialize
        DCylinderData cylData = new DCylinderData();
        cylData.ID = 99;
        cylData.MovingTime = 1.1;
        cylData.CylinderType = ECylinderType.UPSTREAM_DOWNSTREAM;
        cylData.Solenoid = new int[]{ 2, 3};
        for (int i = 0; i < 2 ; i++)
        {
            cylData.Solenoid[i] = i + 2;
            cylData.nameTest[i] = $"NameTest_{i}";
        }
        for (int i = 0; i < DEF_MAX_CYLINDER_SENSOR; i++)
        {
            cylData.UpSensor[i] = i * 1;
            cylData.DownSensor[i] = i * 4;
        }
        for (int i = 0; i < cylData.TwoDimension.GetLength(0) ; i++)
        {
            for (int j = 0; j < cylData.TwoDimension.GetLength(1) ; j++)
            {
                cylData.TwoDimension[i, j] = i * cylData.TwoDimension.GetLength(1) + j;
            }
        }
        cylData.boolTest[0] = true;
        cylData.boolTest[1] = false;
        cylData.boolTest[2] = true;

        // 1. Class -> Dictionary
        Dictionary<string, string> fieldBook = new Dictionary<string, string>();

        Type type = typeof(DCylinderData);
        FieldInfo[] fields = type.GetFields();
        foreach (FieldInfo field in fields)
        {
            // 1.1 element
            if (field.FieldType.IsValueType)
            {
                fieldBook.Add(field.Name, field.GetValue(cylData).ToString());
            }
            // 1.2 array
            else if (field.FieldType.IsArray)
            {
                Array array = (Array)field.GetValue(cylData);

                // 1.2.1 1-D array
                if (array.Rank == 1)
                {
                    for (int i = 0; i < array.GetLength(0); i++)
                    {
                        fieldBook.Add($"{field.Name}__{i}", array.GetValue(i).ToString());
                    }
                }
                // 1.2.2 2-D array
                else if (array.Rank == 2)
                {
                    for (int i = 0; i < array.GetLength(0); i++)
                    {
                        for (int j = 0; j < array.GetLength(1); j++)
                        {
                            fieldBook.Add($"{field.Name}__{i}__{j}", array.GetValue(i, j).ToString());
                        }
                    }
                }
                else
                {
                    WriteLine($"Not support {field.Name}'s array {array.Rank} dimension.");
                }
            }
            else
            {
                WriteLine($"Not support to handle {field.Name}'s {field.FieldType.ToString()}");
            }
        }

        // 2. print Dictionary
        foreach (KeyValuePair<string, string> item in fieldBook)
        {
            WriteLine($"FieldBook {item.Key} : {item.Value}");
        }

        // 3. Dictionary -> Class
        DCylinderData copyData = new DCylinderData();
        foreach (FieldInfo field in fields)
        {
            // 3.1 handle element
            if (field.FieldType.IsValueType && fieldBook.ContainsKey(field.Name))
            {
                SetFieldValue(copyData, field, fieldBook[field.Name]);
            }
            // 3.2 handle array
            else if (field.FieldType.IsArray)
            {
                Array array = (Array)field.GetValue(copyData);
                string key, value;

                // 3.2.1 1-D array
                if (array.Rank == 1)
                {
                    var arr_1d = new string[array.GetLength(0)];
                    for (int i = 0; i < array.GetLength(0); i++)
                    {
                        key = $"{field.Name}__{i}";
                        value = fieldBook.ContainsKey(key) ? fieldBook[key] : "";
                        arr_1d.SetValue(value, i);
                    }
                    SetFieldValue(copyData, field, arr_1d);
                }
                // 3.2.1 2-D array
                else if (array.Rank == 2)
                {
                    var arr_2d = new string[array.GetLength(0), array.GetLength(1)];
                    for (int i = 0; i < array.GetLength(0); i++)
                    {
                        for (int j = 0; j < array.GetLength(1); j++)
                        {
                            key = $"{field.Name}__{i}__{j}";
                            value = fieldBook.ContainsKey(key) ? fieldBook[key] : "";
                            arr_2d.SetValue(value, i, j);
                        }
                    }
                    SetFieldValue(copyData, field, arr_2d);
                }
                else
                {
                    WriteLine($"Not support {field.Name}'s array {array.Rank} dimension.");
                }
            }
            // 3.3 not support
            else
            {
                WriteLine($"Not support to handle {field.Name}'s {field.FieldType.ToString()}");
            }
        }

        WriteLine("Press any key to continue");
        ReadLine();

そして、これらのような SetFieldValue 関数

        public static void SetFieldValue(Object target, FieldInfo fieldInfo, string value)
    {
        string fieldType = fieldInfo.FieldType.Name;
        fieldType = fieldType.ToLower();

        switch (fieldType)
        {
            case "boolean":
                bool b;
                fieldInfo.SetValue(target, bool.TryParse(value, out b) ? b : false);
                break;

            case "int32":
                int n;
                fieldInfo.SetValue(target, int.TryParse(value, out n) ? n : 0);
                break;

            case "double":
                double d;
                fieldInfo.SetValue(target, double.TryParse(value, out d) ? d : 0);
                break;

            case "string":
                fieldInfo.SetValue(target, value);
                break;
        }
    }

    public static void SetFieldValue(Object target, FieldInfo fieldInfo, string[] arr)
    {
        string fieldType = fieldInfo.FieldType.Name;
        fieldType = fieldType.ToLower();
        fieldType = fieldType.Replace("[]", "");

        switch (fieldType)
        {
            case "boolean":
                bool b;
                bool[] arr_b = Array.ConvertAll(arr, s => bool.TryParse(s, out b) ? b : false);
                fieldInfo.SetValue(target, arr_b);
                break;

            case "int32":
                int n;
                int[] arr_n = Array.ConvertAll(arr, s => int.TryParse(s, out n) ? n : 0);
                //int[] arr_n1 = Array.ConvertAll(arr, int.Parse);
                //int[] arr_n2 = arr.Select(s => int.TryParse(s, out n) ? n : 0).ToArray();
                fieldInfo.SetValue(target, arr_n);
                break;

            case "double":
                double d;
                double[] arr_d = Array.ConvertAll(arr, s => double.TryParse(s, out d) ? d : 0);
                fieldInfo.SetValue(target, arr_d);
                break;

            case "string":
                fieldInfo.SetValue(target, arr);
                break;
        }
    }

    public static void SetFieldValue(Object target, FieldInfo fieldInfo, string[,] arr)
    {
        string fieldType = fieldInfo.FieldType.Name;
        fieldType = fieldType.ToLower();
        fieldType = fieldType.Replace("[,]", "");

        // 0. string return
        switch (fieldType)
        {
            case "string":
                fieldInfo.SetValue(target, arr);
                return;
                break;
        }

        // 1. initialize
        int n;
        double d;
        bool b;

        //object[,] output = new object[arr.GetLength(0), arr.GetLength(1)];
        int[,] output_n = new int[arr.GetLength(0), arr.GetLength(1)];
        bool[,] output_b = new bool[arr.GetLength(0), arr.GetLength(1)];
        double[,] output_d = new double[arr.GetLength(0), arr.GetLength(1)];

        // 2. convert
        for (int i = 0; i < arr.GetLength(0); i++)
        {
            for (int j = 0; j < arr.GetLength(1); j++)
            {
                switch (fieldType)
                {
                    case "boolean":
                        output_b[i, j] = bool.TryParse(arr[i, j], out b) ? b : false;
                        break;

                    case "int32":
                        output_n[i, j] = int.TryParse(arr[i, j], out n) ? n : 0;
                        break;

                    case "double":
                        output_d[i, j] = double.TryParse(arr[i, j], out d) ? d : 0;
                        break;
                }
            }
        }

        // 2. setvalue
        //fieldInfo.SetValue(target, output);
        switch (fieldType)
        {
            case "boolean":
                fieldInfo.SetValue(target, output_b);
                break;

            case "int32":
                fieldInfo.SetValue(target, output_n);
                break;

            case "double":
                fieldInfo.SetValue(target, output_d);
                break;
        }
    }

これはすべて私のコードの一部です。

4

1 に答える 1

1

GetElementType、、および(オプション)Array.CreateInstanceが必要です。例外や不明な型、文字列内のエラーに対応する必要があるため、それを行うにはまだかなりの量のコードが必要です。TypeDescriptor.GetConverterdynamic

質問に答えるために、次の 3 つのことを行うことができます。

で始まる 3 行string fieldType = fieldInfo.FieldType.Name;を 1 行に置き換えます。string fieldType = fieldInfo.FieldType.GetElementType().Name;

次に、1D 配列の出力を次のように置き換えます。

dynamic output = Array.CreateInstance(fieldInfo.FieldType.GetElementType(), arr.GetLength(0));

そして、あなたの2D配列出力は次のとおりです:

dynamic output = Array.CreateInstance(fieldInfo.FieldType.GetElementType(), arr.GetLength(0), arr.GetLength(1));

しかし、ここが難しいところです。fieldInfo から「型変換」関数を作成し、それを for ループで使用する必要があります。ただし、変換先のタイプを正確に知らなくても、「ボックス化解除」して目的のタイプに反対することはできません。残念ながら、ケースステートメント(または同様のもの)が必要になります。基本的には配列が問題ですが、必要な switch ステートメントは 1 つだけです。

var converter = TypeDescriptor.GetConverter(fieldInfo.FieldType.GetElementType());
for (int i = 0; i < arr.GetLength(0); i++)
{
    for (int j = 0; j < arr.GetLength(1); j++)
    {
        switch (fieldType)
        {
            case "Int32":
                output[i,j] = (int)converter.ConvertFromString(arr[i,j]);
                break;
            ...
        }
    }
}

fieldInfo.SetValue(target, output);

これは、本質的にシリアル化しているものにとって非常に多くの労力です。より良い解決策は次のとおりです。

  1. まず、Json.NET を NuGet からプロジェクトに取得します
  2. // 1. Class -> Dictionaryセクションを次のように置き換えますstring output = JsonConvert.SerializeObject(cylData);
  3. クラスを元に戻すには:JsonConvert.DeserializeObject<DCylinder>(output);

2行のコードで解決:)


それ以外はCode Reviewに投稿してください。

于 2016-01-25T15:01:52.747 に答える