繁体   English   中英

使用IEnumerable类型的参数调用C#方法 <string> 在Powershell

[英]Calling a C# method with argument of type IEnumerable<string> in Powershell

我正在使用PowerShell的Box.V2 SDK。 我打电话给这里记录的方法:

https://github.com/box/box-windows-sdk-v2/blob/master/Box.V2/Managers/BoxUsersManager.cs

这是我的代码:

# Load Assemblies
[Reflection.Assembly]::LoadFile("C:\Users\jfrank\Documents\BoxSDKV2\System.IdentityModel.Tokens.Jwt.5.1.4\lib\net45\System.IdentityModel.Tokens.Jwt.dll")
[Reflection.Assembly]::LoadFile("C:\Users\jfrank\Documents\BoxSDKV2\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll")
[Reflection.Assembly]::LoadFile("C:\Users\jfrank\Documents\BoxSDKV2\Box.V2.3.3.0\lib\net45\Box.V2.dll")
[Reflection.Assembly]::LoadFile("C:\Users\jfrank\Documents\BoxSDKV2\Microsoft.IdentityModel.Logging.1.1.4\lib\net45\Microsoft.IdentityModel.Logging.dll")
[Reflection.Assembly]::LoadFile("C:\Users\jfrank\Documents\BoxSDKV2\Microsoft.IdentityModel.Tokens.5.1.4\lib\net45\Microsoft.IdentityModel.Tokens.dll")
[Reflection.Assembly]::LoadFile("C:\Users\jfrank\Documents\BoxSDKV2\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll")
[Reflection.Assembly]::LoadFile("C:\Users\jfrank\Documents\BoxSDKV2\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll")

# Configure
$jsonConfig = Get-content "C:\Users\jfrank\Documents\WindowsPowerShell\Scripts\Box\config.json" | ConvertFrom-Json
$boxConfig = New-Object Box.V2.config.BoxConfig (($jsonConfig.boxAppSettings).clientID, ($jsonConfig.boxAppSettings).clientSecret, $jsonConfig.enterpriseID, (($jsonConfig.boxAppSettings).appAuth).privateKey, (($jsonConfig.boxAppSettings).appAuth).passphrase, (($jsonConfig.boxAppSettings).appAuth).publicKeyID)
$boxJWT = New-Object Box.V2.JWTAuth.BoxJWTAuth ($boxConfig)

# Authenticate
$adminToken = $boxJWT.AdminToken()
$adminClient = $boxJWT.AdminClient($adminToken)

# Get Users
$enterpriseUsers = $adminClient.UsersManager.GetEnterpriseUsersAsync().Result

# Get Admin by name
Foreach ($entry in $enterpriseUsers.Entries) {
    if ($entry.Name -eq "Johannes Frank") {
            $admin = $entry
        }
    }

# Get User
$userToken = $boxJWT.UserToken($admin.Id)
$userClient = $boxJWT.UserClient($userToken, $admin.Id)


$fields = [System.Collections.Generic.IEnumerable`1[System.String]]"role, enterprise"

$userClient.UsersManager.GetCurrentUserInformationAsync($fields).Result | Format-List

没有参数$ fields,最后一行完美无缺。 但使用参数调用是乏味的。

我目前正在获得其他尝试以下错误消息:

GAC    Version        Location                                                                                                             
---    -------        --------                                                                                                             
False  v4.0.30319     C:\Users\jfrank\Documents\BoxSDKV2\System.IdentityModel.Tokens.Jwt.5.1.4\lib\net45\System.IdentityModel.Tokens.Jwt...
False  v1.1.4322      C:\Users\jfrank\Documents\BoxSDKV2\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll                                    
False  v4.0.30319     C:\Users\jfrank\Documents\BoxSDKV2\Box.V2.3.3.0\lib\net45\Box.V2.dll                                                 
False  v4.0.30319     C:\Users\jfrank\Documents\BoxSDKV2\Microsoft.IdentityModel.Logging.1.1.4\lib\net45\Microsoft.IdentityModel.Logging...
False  v4.0.30319     C:\Users\jfrank\Documents\BoxSDKV2\Microsoft.IdentityModel.Tokens.5.1.4\lib\net45\Microsoft.IdentityModel.Tokens.dll 
False  v4.0.30319     C:\Users\jfrank\Documents\BoxSDKV2\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll                              
False  v4.0.30319     C:\Users\jfrank\Documents\BoxSDKV2\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll                               
Cannot convert the "role, enterprise" value of type "System.String" to type "System.Collections.Generic.IEnumerable`1[System.String]".
At C:\Users\jfrank\Documents\WindowsPowerShell\Scripts\Box\BoxJWTAuth.ps1:34 char:1
+ $fields = [System.Collections.Generic.IEnumerable`1[System.String]]"r ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : ConvertToFinalInvalidCastException

Cannot convert argument "fields", with value: "Box.V2.Models.BoxUser", for "GetCurrentUserInformationAsync" to type 
"System.Collections.Generic.IEnumerable`1[System.String]": "Cannot convert the "Box.V2.Models.BoxUser" value of type 
"Box.V2.Models.BoxUser" to type "System.Collections.Generic.IEnumerable`1[System.String]"."
At C:\Users\jfrank\Documents\WindowsPowerShell\Scripts\Box\BoxJWTAuth.ps1:36 char:1
+ $userClient.UsersManager.GetCurrentUserInformationAsync($fields).Resu ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

有人能告诉我怎么称呼这个

public async Task<BoxUser> GetCurrentUserInformationAsync(IEnumerable<string> fields = null)

方法及其参数字段?

编辑:你会在那里找到答案:[string []]作为正确的类型转换。 还有另外两种方式。

个人评论:但我现在真的更重视Python。 而Python不是GW Basic。 我也有类型安全。 花费(浪费)的时间来为参数获取值。 在compenstation中我获得了什么样的“安全性”并且还没有完全理解“通用类型”的原因? 无论如何,我打算进行单元测试。 如果有人喜欢评论这个系统的优势,我很乐意学习。

我真的看不出这些问题是如何相关的。 我以前读过这个答案,我最初的尝试来自那个答案。 我花了(可能浪费了)时间试图做那个单一的类型转换。 在python中,我会立即分配并拥有正确的类型。 你能解释为什么这些问题是相关的,我通过这种类型的“安全”获得了什么?

你没有获得任何安全保障。 您正在使用原始泛型类创建非常特定类型的对象。 当你需要这样做时,情况非常狭窄,这就是为什么它并不容易。

看,我从未使用过box-windows-sdk-v2。 但是,您的代码告诉我,我需要加载七个程序集,并将现有的JSON配置文件仅用于实例Box.V2.config.BoxConfig 我甚至没有Box用户帐户。 了解某人设置仅测试代码是不合理的。

我看到的是此错误消息:

“无法将类型为”Box.V2.Models.BoxUser“的”Box.V2.Models.BoxUser“值转换为”System.Collections.Generic.IEnumerable`1 [System.String]“

现在,你的问题和你问的方式让我相信你明白IEnumerable<T>是什么。 但是,现在,我不认为你这样做,所以你没有尝试过我已经尝试过的东西。

@Andrei的答案是构建自己的自定义类来实现IEnumerable而不是使用已经完成的任何现有类。 但是,根据您提出问题的方式, 这就是您所要求的

那么,让我们从头开始:

IList<T>ICollection<T>IEnumerable<T>是对象的通用接口 它们是C#中的原始类型,允许您构造自定义集合类型。 它们也由内置的通用集合类型实现,如List<T>Stack<T>以及Dictionary<TKey, TValue> 这意味着如果你需要编写一个需要枚举集合的C#方法,你可以使用IEnumerable<T>类型编写它,只要该集合实现了IEnumerable<T> ,它就能枚举任何对象集合。 IEnumerable<T>界面。 甚至System.Array也被扩展为包含这些类型 ,但有些方法会失败:

一维数组实现System.Collections.Generic.IList,System.Collections.Generic.ICollection,System.Collections.Generic.IEnumerable,System.Collections.Generic.IReadOnlyList和System.Collections.Generic.IReadOnlyCollection通用接口。 这些实现在运行时提供给数组,因此,泛型接口不会出现在Array类的声明语法中。 此外,没有关于接口成员的参考主题,只能通过将数组转换为通用接口类型(显式接口实现)来访问它们。 将数组转换为其中一个接口时要注意的关键是添加,插入或删除元素的成员会抛出NotSupportedException。

所以,你的错误信息是什么,“我需要一个对象,它是一个实现IEnumerable<T>接口的System.String的集合。”

这意味着我假设你最初尝试过其中一种:

$fields = "role", "enterprise"  # Creates a [System.Object[]], so should error

$fields = @("role", "enterprise")  # Creates a [System.Object[]], so should error

PowerShell中的默认数组是[System.Object[]]类型,因为PowerShell尝试尽可能通用。 PowerShell的命令都接受该类型。 但是,当您从已加载的库中调用对象方法时,您实际上是在C#land中工作,而不是在PowerShell中工作。 你必须制作符合C#要求的对象。 这就是为什么你感觉自己正在写一个迷雾,系统没有说清楚它想要什么。 您实际上是在使用PowerShell编写C#代码(尝试静态类型)(尝试不进行静态类型化)。

这里的问题是.Net Framework中没有内置的方法可以自动将[Object []]转换为实现[IEnumerable [String]]的东西。 就像你不能说'Hello' + 1 + 'World' ,在Python中,该语言不知道如何为你进行转换。

如果以上任何一项都不起作用,您应该尝试以下任何一项

$fields = [System.String[]]("role", "enterprise")  # Creates a [System.String[]], so may work
# [System.String[]] implements [IEnumerable[String]], but not completely

$fields = [System.Collections.Generic.List[System.String]]("role", "enterprise")
# Creates a [List[String]], and should work because that implements [IEnumerable[String]]

$fields = New-Object -TypeName "System.Collections.Generic.List[System.String]"
$fields.Add('role')
$fields.Add('enterprise')
# Also creates a [List[String]]

$fields = New-Object -TypeName "System.Collections.Generic.Stack[System.String]"
$fields.Push('role')
$fields.Push('enterprise')
# Creates a [Stack[String]], and should work because that also implements [IEnumerable[String]]

$fields = New-Object -TypeName "System.Collections.Generic.HashSet[System.String]"
[void]$fields.Add('role')
[void]$fields.Add('enterprise')

# See also System.Collections.Generic.Queue, System.Collections.Generic.SortedSet, System.Collections.Generic.LinkedList, etc.

但是我不知道Box.V2.Models.BoxUser是做什么的,也不知道对象有多挑剔。 可能真的需要原始的泛型,这就是我所假设的,因为你在尝试创建它时经历了很多麻烦。 这显然也是这里的另一个答案。

至于“当Python如此简单时,为什么PowerShell如此复杂?”:

好吧,你不是在这个脚本中编写PowerShell。 你不是。 PowerShell看起来像这样:

Get-ChildItem *.pdf -File | Where-Object {
    $_.LastWriteTime -lt $CutoffDate
} | Move-Item -Destination C:\archive\ -Verbose

你在这里做的是使用PowerShell编写解释性的C#。 您可以这样做,因为PowerShell为您提供了对.Net Framework的完全访问权限,但使用第三方库是一个高级PowerShell主题。 它根本不应该是你写的第一个脚本。 它大约有30%的PowerShell和70%的C#,你真的需要至少对两者的理解,因为一旦你开始调用第三方库,许多使PowerShell快速且易于使用的约定根本不起作用。

您必须明白使用PowerShell执行此操作会起作用,但不是您的任何库的作者都希望您使用它。 PowerShell不是C#。 你会遇到奇怪的库,它没有以PowerShell可以正常工作的方式实现,因为通过使用PowerShell来实现它,你自动将自己置于一个大约1%使用该库的开发人员的组中。 PowerShell的约定不会 100%与C#和第三方库的约定保持一致。

&{ # About this http://community.idera.com/powershell/powertips/b/tips/posts/using-custom-scopes
  $OFS=', ' # About $OFS https://blogs.msdn.microsoft.com/powershell/2006/07/15/psmdtagfaq-what-is-ofs/
  $PSVersionTable # The Powershell version and not only https://stackoverflow.com/questions/1825585/determine-installed-powershell-version
# The way number one to takle the problem
  $fields = [activator]::createinstance([System.Collections.Generic.List``1].makegenerictype([System.String]))
  $fields.AddRange([string[]]("role", "enterprise"))
# The next three lines are needed just to show the result
  $fields.gettype().fullname
  $fields.gettype().getInterfaces() | ?{$_.Name.startswith('IEnumerable') -and $_.IsGenericType} | Select -ExpandProperty FullName
  """${fields}"""
  rv fields # rv is the alias of Remove-Variable cmdlet
# The way number two
  $fields = [System.Collections.Generic.List[System.String]][string[]]("role", "enterprise")
  $fields.gettype().fullname
  $fields.gettype().getInterfaces() | ?{$_.Name.startswith('IEnumerable') -and $_.IsGenericType} | Select -ExpandProperty FullName
  """${fields}"""
  rv fields
# The way number three
  $fields = [string[]]("role", "enterprise")
  $fields.gettype().fullname
  $fields.gettype().getInterfaces() | ?{$_.Name.startswith('IEnumerable') -and $_.IsGenericType} | Select -ExpandProperty FullName
  """${fields}"""
}
Name                           Value
CLRVersion                     2.0.50727.8762
BuildVersion                   6.1.7601.17514                                                                                                                                                                                          
PSVersion                      2.0
WSManStackVersion              2.0
PSCompatibleVersions           {1.0, 2.0}                                                                                                                                                                                                                          
SerializationVersion           1.1.0.1
PSRemotingProtocolVersion      2.1                                                                                                                                                                                                                                 
System.Collections.Generic.List`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
System.Collections.Generic.IEnumerable`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
"role, enterprise"
System.Collections.Generic.List`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
System.Collections.Generic.IEnumerable`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
"role, enterprise"
System.String[]
System.Collections.Generic.IEnumerable`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
"role, enterprise"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM