【问题标题】:LINQ - Select property from object array to strongly runtime type array?LINQ - 从对象数组中选择属性到强运行时类型数组?
【发布时间】:2019-12-29 19:24:37
【问题描述】:

尝试通过数组绑定(Oracle)改进插入方法,该方法需要将强类型与 Array.

第一步,我需要List<object>到每个属性Array。 但是,当我使用 LINQ 到Select 属性然后ToArray() 时,我得到了object[]

//Reflection
foreach(var prop in typeof(Person).GetProperties())
    personList.Select(x => prop.GetValue(x)).ToArray();

看起来不能使用泛型ToArray<T>() 来处理运行时属性类型。

代码 https://dotnetfiddle.net/7ogYNJ

using System;
using System.Collections.Generic;
using System.Linq;              
using System.Reflection;
using System.Diagnostics;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Program
{
    public static void Main()
    {

        List<Person> personList = new List<Person>();
        personList.Add(new Person(){Name = "aaa", Age = 10});
        personList.Add(new Person(){Name = "bbb", Age = 5});
        for(int i = 0; i< 10; i++)
        {
            personList.AddRange(personList);
        }


        Dictionary<string, PropertyInfo> propDict = typeof(Person).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => p.CanRead && !p.GetIndexParameters().Any()).AsEnumerable().ToDictionary(x => x.Name, x => x);
        int count = personList.Count;

        Stopwatch sw = new Stopwatch();
        //1. get Object[]
        sw.Restart();
        foreach(var prop in propDict)
        {
            var tempArray = personList.Select(x => prop.Value.GetValue(x)).ToArray();
            Console.WriteLine(tempArray.GetType().Name);//Object[]
        }
        sw.Stop();
        Console.WriteLine("Spend" + sw.ElapsedMilliseconds + "us");

        //2. not work, return Object[]
        sw.Restart();
        foreach(var prop in propDict)
        {
            var tempArray = personList.Select(x => Convert.ChangeType(prop.Value.GetValue(x), prop.Value.PropertyType)).ToArray();
            Console.WriteLine(tempArray.GetType().Name);//Object[]
        }
        sw.Stop();
        Console.WriteLine("Spend" + sw.ElapsedMilliseconds + "us");

        //3. work, via ArrayCopy, try to find other method
        sw.Restart();
        foreach(var prop in propDict)
        {
            var tempArray = personList.Select(x => prop.Value.GetValue(x)).ToArray();
            Array stronglyTypeArray = Array.CreateInstance(prop.Value.PropertyType, count);
            Array.Copy(tempArray, stronglyTypeArray, count);
            Console.WriteLine(stronglyTypeArray.GetType().Name);//String[]//Int32[]
        }
        sw.Stop();
        Console.WriteLine("Spend" + sw.ElapsedMilliseconds + "us");

        //4. work, if-condition slower than method 3
        sw.Restart();
        foreach(var prop in propDict)
        {
            dynamic tempArray;
            if(prop.Value.PropertyType == typeof(System.String))
            {
                tempArray = personList.Select(x =>  prop.Value.GetValue(x).ToString()).ToArray();
            }
            else if(prop.Value.PropertyType == typeof(System.Boolean))
            {
                tempArray = personList.Select(x =>  (bool)prop.Value.GetValue(x)).ToArray();
            }
            else if(prop.Value.PropertyType == typeof(System.Byte))
            {
                tempArray = personList.Select(x =>  (byte)prop.Value.GetValue(x)).ToArray();
            }
            else if(prop.Value.PropertyType == typeof(System.Char))
            {
                tempArray = personList.Select(x =>  (char)prop.Value.GetValue(x)).ToArray();
            }
            else if(prop.Value.PropertyType == typeof(System.Decimal))
            {
                tempArray = personList.Select(x =>  (decimal)prop.Value.GetValue(x)).ToArray();
            }
            else if(prop.Value.PropertyType == typeof(System.Double))
            {
                tempArray = personList.Select(x =>  (double)prop.Value.GetValue(x)).ToArray();
            }
            else if(prop.Value.PropertyType == typeof(System.Int16))
            {
                tempArray = personList.Select(x =>  (short)prop.Value.GetValue(x)).ToArray();
            }
            else if(prop.Value.PropertyType == typeof(System.Int32))
            {
                tempArray = personList.Select(x =>  (int)prop.Value.GetValue(x)).ToArray();
            }
            else if(prop.Value.PropertyType == typeof(System.Int64))
            {
                tempArray = personList.Select(x =>  (long)prop.Value.GetValue(x)).ToArray();
            }
            else if(prop.Value.PropertyType == typeof(System.Single))
            {
                tempArray = personList.Select(x =>  (float)prop.Value.GetValue(x)).ToArray();
            }
            else
            {
                tempArray = personList.Select(x =>  prop.Value.GetValue(x)).ToArray();
            }
            Console.WriteLine(tempArray.GetType().Name);//Object[]
        }
        sw.Stop();
        Console.WriteLine("Spend" + sw.ElapsedMilliseconds + "us");
    }
}

在方法2中,我尝试使用Convert.Change,但它不起作用。
在方法 3 中,通过Array.CreateInstanceArrayCopy,它可以工作。
方法四中,使用if-condition进行强制转换,但比方法三慢,无法处理非预期类型。

我的候选人是方法 3。 有没有更有效的方法来使用 Array 获取强类型?

顺便说一句,有一个delegate方法可以更快地获取属性值https://stackoverflow.com/a/17440469/12620047

【问题讨论】:

  • 为什么不对每个属性使用var nameArray = personList.Select(t=&gt;t.Name).ToArray()?你想创建一个通用的方法来处理它吗?
  • @Eldar,我想创建一个通用方法 public void someMethod(List InputList)。所以,我不能直接选择属性。相反,我通过反射 typeof(Person).GetProperty("Name").GetValue(x) 获取属性数组
  • 你知道GetValue()返回的类型吗?这是否解释了为什么ToArray() 返回的类型是object[]?同样,Convert.ChangeType() 的返回类型是什么?知道(编译时)类型是成功的一半。

标签: c# arrays linq reflection


【解决方案1】:

如何打开类型(通常不赞成)并使用Cast&lt;&gt;() 创建正确的Array

foreach (var prop in propDict) {
    var qryProp = personList.Select(x => prop.Value.GetValue(x));
    Array tempArray = null;
    switch (Type.GetTypeCode(prop.Value.PropertyType)) {
        case TypeCode.String:
            tempArray = qryProp.Cast<string>().ToArray();
        break;
        case TypeCode.Int32:
            tempArray = qryProp.Cast<Int32>().ToArray();
        break;
    }
    Console.WriteLine(tempArray.GetType().Name);//String[]/Int32[]
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    • 2015-10-30
    相关资源
    最近更新 更多