簡體   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