簡體   English   中英

C#如何在不進行手動類型轉換的情況下調用FieldInfo.SetValue函數

[英]C# How to call FieldInfo.SetValue function without manual type conversion

我想將數據類實例保存到數據庫並從數據庫加載它。 我想自動生成sql命令。 所以,我認為我需要使用dictionary <string,string>來解決它。

請參閱我的老問題: 如何將2D字符串數組轉換為2D [int,double,bool,..]數組?

這樣的工作過程。

  1. 將數據類實例轉換為字典<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;
        }
    }

這都是我的代碼的一部分。

您將需要GetElementTypeArray.CreateInstanceTypeDescriptor.GetConverterdynamic (可選)。 您仍然需要大量代碼來執行此操作,因為您需要迎合異常和未知類型以及字符串中的錯誤。

要回答您的問題,您可以做三件事:

替換以string fieldType = fieldInfo.FieldType.Name;開始的3行string fieldType = fieldInfo.FieldType.Name; 一行: string fieldType = fieldInfo.FieldType.GetElementType().Name;

然后將您的一維數組輸出替換為:

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循環中。 但是您不能在不確切知道要轉換為哪種類型的情況下“拆箱”並反對所需的類型。 因此,不幸的是,您將需要案例陳述(或類似的陳述)。 基本上,數組是問題所在,盡管現在您只需要1條switch語句:

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. 首先從NuGet獲取Json.NET到您的項目中
  2. string output = JsonConvert.SerializeObject(cylData);替換// 1. Class -> Dictionary string output = JsonConvert.SerializeObject(cylData); // 1. Class -> Dictionary部分string output = JsonConvert.SerializeObject(cylData);
  3. 取回該類: JsonConvert.DeserializeObject<DCylinder>(output);

解決了兩行代碼:)


除此之外,您應該將其發布在Code Review中

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM