【发布时间】:2020-08-08 11:03:09
【问题描述】:
我通过 Powershell 将一个非常大的 CSV 表导入到对象数组中。 每个对象可能看起来像这样的定义:
$test = [PsCustomObject]@{id='1';name='a'}
问题是,所有类型都是“字符串”,我需要稍后在我的代码中使用正确的类型。为此,我想使用嵌入式 C# 代码将所有对象属性的值转换为字符串数组,以将其值添加到具有正确类型定义的 DataTable 中。
我现在在 C# 部分苦苦挣扎。这是我的代码示例,它不起作用。 如何更改 C# 部分以将对象值转换为数组?
# this code should convert the object-values into an array:
Add-Type -ReferencedAssemblies System.Data -TypeDefinition '
using System;
public class row {
public object[] row(object test) {
int id = Int32.Parse(test.id);
string name = test.name;
return (id, name);
}
}'
# this is the test-object:
$test = [PsCustomObject]@{id='1';name='a'}
# this is the final table with correct types:
$table = [System.Data.DataTable]::new()
[void]$table.Columns.Add('id', [int])
[void]$table.Columns.Add('name', [string])
# at the end it should work like this:
$row = [row]::new($test)
$table.Rows.Add($row)
我在没有 C# 的情况下做了一些测试,但这很慢。 例如。这个简单的循环(即使没有将数据添加到行中)运行超过 20 秒:
$test = [PsCustomObject]@{id='1';name='a'}
foreach($x in 1..1MB) {
$row = foreach($i in $test.PsObject.Properties.Value){if ($i) {$i} else {$null}}
#[void]$table.rows.Add($row)
}
所以理论上我需要在最后一个代码块中做同样的事情,但通过嵌入式 Csharp 代码。
我怎样才能以有效的方式完成这项工作?
更新 #1: 感谢 Theo 的输入,我可以加快转换速度。我没想到这会比仅查询 PsObject-properties 快 5 倍。例如。事实证明,“else”语句比首先分配 var 要慢。下面是对比代码:
$test = [PsCustomObject]@{id='1';name='a'}
foreach($x in 1..1MB) {
$id = $test.id
if ([string]::IsNullOrEmpty($id)){$id = $null}
$name = $test.name
$row = @($id, $name)
}
但它仍然是我整个代码中最慢的部分,我仍在寻找智能 C# 解决方案。我的想法是,如果稍后输入对象有任何其他属性,那么我可以动态重建 C# 代码。这不适用于纯 PS 代码。
更新 #2: 根据 BACON 的输入,我能够使用 C# 代码解决挑战。 这是我的工作实现:
Add-Type -TypeDefinition '
using System;
public class test {
public string id {get;set;}
public string name {get;set;}
}
public static class DataParser {
public static string[] ParseToArray(test data) {
string id = data.id;
if (String.IsNullOrEmpty(id)) {id = null;};
string name = data.name;
return new string[] {id,name};
}
}'
# this is the test-object:
$test = [PsCustomObject]@{id='';name='a'}
$timer = [System.Diagnostics.Stopwatch]::StartNew()
foreach($x in 1..1MB) {
$row = [DataParser]::ParseToArray($test)
}
$timer.Stop()
$timer.Elapsed.TotalSeconds
我没想到的是这个解决方案的运行时间——它比我上面发布的纯 PowerShell 版本慢得多。所以我的结论是“任务完成”,但我们错过了目标。这意味着没有真正有效的方法将对象值转换为数组。
因此,我将不再将 CSV 数据作为对象导入,而是专注于通过“dataSet.readXML”将大型数据作为 XML 导入。我只希望有一个内置选项可以直接将 CSV 数据导入为数组或 dataRows。
【问题讨论】:
-
并非如此。我需要将几十万个上述格式的对象插入到数据表中。这就是为什么我正在寻找通过 CSharp 实现从属性值转换为可用于创建数据行的数组的原因。
-
我如何才能获得与我遇到的真正挑战相关的问题的负面评价?
-
我猜,你的问题(最初)被否决了,就像XY Problem 一样,从你的结论中也可以看出。为什么要将其转换为 DataTable?是什么让您认为您的 C# 类将胜过本机 PowerShell?如果您通过 PowerShell 管道正确地流式传输对象,您可以节省大量内存,它可能会更快,但您不会显示任何“慢”的东西。顺便说一句,实际问题源于不支持字符串以外的任何其他类型的 csv 文件(不是 PowerShell)。您可以简单地使用计算表达式:
-
.. | Select-Object @{n='ID'; e={ [Int]$_.ID }}, Name | ...
标签: c# performance powershell csv datatable