拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 具有动态指定资料型别的PowerShell中的LINQ

具有动态指定资料型别的PowerShell中的LINQ

白鹭 - 2022-02-10 2110 0 0

在回答我之前的问题时,我得到了一个作业脚本,它基于字面上指定为[int].

现在我想动态更改资料型别是否可以?

uj5u.com热心网友回复:

上一个问题答案使用型别文字( [...]),它要求所有型别都逐字指定(通过它们的文字名称)。

  • 型别文字支持变量参考[Func[Data.DataRow, $columnType]]作业-它会导致一个语法错误

要基于动态确定(间接指定)的型别来概括链接的答案,需要进行两项修改:

  • 您必须通过.MakeArrayType()and .MakeGenericType()方法构造(实体化)LINQ 方法呼叫中涉及的封闭泛型型别

  • 您必须使用-as时,有条件的型别转换运算子投输入物件/转换脚本块({ ... })这些型别。

# Create a sample data table...
[Data.DataTable] $dt = New-Object System.Data.DataTable
[Data.DataColumn] $column = New-Object System.Data.DataColumn "Id", ([int])
$dt.Columns.Add($column)
# ... and add data.
[Data.DataRow]$row = $dt.NewRow()
$row["Id"] = 1
$dt.Rows.Add($row)
$row = $dt.NewRow() 
$row["Id"] = 2
$dt.Rows.Add($row)

# Using reflection, get the open definition of the relevant overload of the 
# static [Linq.Enumerable]::Select() method.
# ("Open" means: its generic type parameters aren't yet bound, i.e. aren't
# yet instantiated with concrete types.)
$selectMethod = [Linq.Enumerable].GetMethods().Where({ 
  $_.Name -eq 'Select' -and $_.GetParameters()[-1].ParameterType.Name -eq 'Func`2' 
}, 'First')

# Dynamically set the name of the column to use in the projection.
$colName = 'Id'

# Dynamically set the in- and output types to use in the LINQ
# .Select() (projection) operation.
$inType = [Data.DataRow]
$outType = [int]


# Now derive the generic types required for the LINQ .Select() method
# from the types above:

# The array type to serve as the input enumerable.
# Note: As explained in the linked answer, the proper - but more cumbersome -
#       solution would be to use reflection to obtain a closed instance of
#       the generic .AsEnumerable() method.
$inArrayType = $inType.MakeArrayType()

# The type for the 'selector' argument, i.e. the delegate performing
# the transformation of each input object.
$closedFuncType = [Func`2].MakeGenericType($inType, $outType)

# Close the generic .Select() method with the given types
# and invoke it.
[int[]] $results = $selectMethod.MakeGenericMethod($inType, $outType).Invoke(
  # No instance to operate on - the method is static.
  $null,
  # The arguments for the method, as an array.
  # Note the use of the -as operator with the dynamically constructed types.
  (
    ($dt.Rows -as $inArrayType), 
    ({ $args[0].$colName } -as $closedFuncType)
  )
)

# Output the result.
$results

退后一步:

如链接答案所示,PowerShell 的成员列举可以提供相同的功能语法大大简化,无需显式处理型别

# Create a sample data table...
[Data.DataTable] $dt = New-Object System.Data.DataTable
[Data.DataColumn] $column = New-Object System.Data.DataColumn "Id", ([int])
$dt.Columns.Add($column)
# ... and add data.
[Data.DataRow]$row = $dt.NewRow()
$row["Id"] = 1
$dt.Rows.Add($row)
$row = $dt.NewRow() 
$row["Id"] = 2
$dt.Rows.Add($row)

# Dynamically set the name of the column to use in the projection.
$colName = 'Id'

# Use member enumeration to extract the value of the $colName column
# from all rows.
$dt.$colName  # Same as: $dt.Rows.$colName

uj5u.com热心网友回复:

您可能想要备份并问自己为什么要尝试在 PowerShell 中使用 LINQ。提示是,如果它看起来像 C#,则可能有更好的方法来做到这一点。

我假设您是 PowerShell 的新手,因此我将简要介绍一下为什么 LINQ 在与管道结合使用时实际上在 PowerShell 中“更容易”(从技术上讲,它不再是 LINQ,但我认为它看起来确实如此)。

Get-Help *-Object有时尝试使用 PowerShell 提示符。注意到出现的 cmdlet 了吗?Select-Object, Where-Object, Group-Object, 和Sort-Object执行与 LINQ 相同的操作,并且它们的名称符合您的期望。另外,严格来说没有强型别要求。

$data | Where-Object -Property Greeting -Like *howdy* | Select-Object Name,Year,Greeting
标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *