【发布时间】: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.CreateInstance 和ArrayCopy,它可以工作。
方法四中,使用if-condition进行强制转换,但比方法三慢,无法处理非预期类型。
我的候选人是方法 3。 有没有更有效的方法来使用 Array 获取强类型?
顺便说一句,有一个delegate方法可以更快地获取属性值https://stackoverflow.com/a/17440469/12620047
【问题讨论】:
-
为什么不对每个属性使用
var nameArray = personList.Select(t=>t.Name).ToArray()?你想创建一个通用的方法来处理它吗? -
@Eldar,我想创建一个通用方法 public void someMethod
(List 获取属性数组InputList)。所以,我不能直接选择属性。相反,我通过反射 typeof(Person).GetProperty("Name").GetValue(x) -
你知道
GetValue()返回的类型吗?这是否解释了为什么ToArray()返回的类型是object[]?同样,Convert.ChangeType()的返回类型是什么?知道(编译时)类型是成功的一半。
标签: c# arrays linq reflection