9

我知道 Powershell 可以调用 .NET 代码,可能看起来像这样

PS> [Reflection.Assembly]::LoadFile(($ScriptDir + ".\SharpSvn-x64\SharpSvn.dll"))
PS> $SvnClient = New-Object SharpSvn.SvnClient

而且我知道 C# 有out参数的地方,Powershell 有[ref]参数,可能看起来像这样:

PS> $info = $null
PS> $SvnClient.GetInfo($repo.local, ([ref]$info))

True

PS> $info

(...long output snipped...)
NodeKind           : Directory
Revision           : 16298
Uri                : http://server/path/to/remoterepo
FullPath           : C:\path\to\localrepo
(...long output snipped...)

而且我知道在 C# 中您可以重载函数,就像 SharpSvn 库为其SvnClient.Update() 方法所做的那样:

  1. Update(ICollection(String))- 将指定路径递归更新到最新(HEAD)修订版
  2. Update(String)- 递归更新指定路径到最新(HEAD)修订
  3. Update(ICollection(String), SvnUpdateArgs)- 将指定路径更新到指定修订版
  4. Update(ICollection(String), SvnUpdateResult)- 将指定路径递归更新到最新(HEAD)修订版
  5. Update(String, SvnUpdateArgs)- 递归更新指定路径
  6. Update(String, SvnUpdateResult)- 递归更新指定路径到最新(HEAD)修订
  7. Update(ICollection(String), SvnUpdateArgs, SvnUpdateResult)- 将指定路径更新到指定修订版
  8. Update(String, SvnUpdateArgs, SvnUpdateResult)- 递归更新指定路径到最新(HEAD)修订

但是,如果我们想把所有这些放在一起怎么办?例如,如果我想调用第 6 个版本Update(),即接受 String 和 SvnUpdateResult 的版本,其中 SvnUpdateResult 是 C# out 对象?我的第一直觉是尝试这样的事情:

PS> $repopath = "C:\path\to\localrepo"
PS> $update = $null
PS> $svnclient.update($repopath, [ref]$update)

Multiple ambiguous overloads found for "Update" and the argument count: "2".
At line:1 char:18
+ $svnclient.update <<<< ($repopath, [ref]$update)
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest

好的,也许我必须提出论点?

PS> $svnclient.update([string]$repopath, [ref][SharpSvn.SvnUpdateResult]$update)

Multiple ambiguous overloads found for "Update" and the argument count: "2".
At line:1 char:18
+ $svnclient.update <<<< ([string]$repopath, [ref][SharpSvn.SvnUpdateResult]$update)
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest

但这似乎也不起作用。我尝试过的其他事情:

  • 铸造$update[SharpSvn.SvnUpdateResult][ref]- 也就是说,颠倒我铸造它的顺序。这会导致一个错误,指出:“[ref] 只能是类型转换序列中的最终类型。”
  • 在使用它之前投射$update到: . 这导致了我在上面遇到的相同的“多个不明确的重载”错误SharpSvn.SvnUpdateResult$update = [SharpSvn.SvnUpdateResult]$null
  • 在使用它之前投射$update到: . 这会导致错误:“无法将“System.Management.Automation.PSReference”类型的“System.Management.Automation.PSReference”值转换为“SharpSvn.SvnUpdateResult”类型。ref$update = [ref]$null

似乎将其投射两次是问题所在 - 最后一次投射只是覆盖了第一次投射,它们不会相互补充。这是怎么回事?有没有办法两次施放东西?有没有其他方法可以解决这个问题?

提前感谢您的帮助。

4

5 回答 5

1

这可能不是一个理想的解决方案,但您可以使用 Add-Type 并制作一个更 PowerShell 友好的类型来包装 Update 方法。

Add-Type -TypeDefinition "
public class SvnClientEx
{
   public static SvnUpdateResult Update(SvnClient client, string path)
   {
       SvnUpdateResult result; 
       client.Update(path, out result);
       return result; 
   } 
}
"

$result = [SvnClient]::Update($svnClient, $repopath)
于 2012-12-23T20:05:39.750 回答
1

这似乎很难做到正确。

这是什么版本的 PowerShell?是SvnUpdateArgsSvnUpdateResult相关的(即一个类派生自另一个)?我假设不会。

基于我构建的类似场景,使用当前版本(4.0)的 PowerShell,我认为这是可行的:

PS> $repopath = "C:\path\to\localrepo"
PS> [SharpSvn.SvnUpdateResult]$update = $null
PS> $svnclient.Update([string]$repopath, [ref]$update)

但是,我只能让它与其中一个重载一起工作!?不确定是不是巧合,但这是我说$svnclient.Update要查看重载定义时首先列出的重载。

在我的 PowerShell 版本中,如果我将第二个参数设为[ref][SharpSvn.SvnUpdateResult]$update,则重载似乎已正确解决,该方法运行时不会出错,但分配给“out”参数的对象似乎丢失了。

即使$repopath被声明为类型安全的[string]$repopath = "C:\path\to\localrepo",似乎我们[string]$repopath在传递它时仍然需要再说一遍(按值)。

于 2015-06-04T11:23:54.057 回答
1

当您使用类的 out 参数调用的方法和具有类似签名的另一个重载(该类可以是此签名中的任何类)时,PowerShell 中似乎存在问题。

我为这个问题创建了一个简单的重现,并为 PowerShell提交了一个问题

于 2016-12-28T04:27:56.327 回答
0

您可以简单地使用代码块并访问此块中的结果(输出)对象:

PS> $repopath = "C:\path\to\localrepo"
PS> $svnclient.update($repopath, { 
      Write-Host $_.Revision
      Write-Host $_.HasRevision
      # Access all the Member and Methods of the result object here
    })
于 2015-05-19T13:11:17.700 回答
0

你可以做几件事:

首先,返回的结果$svnclient.update是 a PSMethodPSMethodInvoke方法。你可以尝试使用它。

其次,如果这不起作用,您可以使用真正的反射:

# To get all methods:
$svnclient.gettype().getmethods()     

# Then filter the results to get overload you need.
# Use GetParameters to get parameters of an overloaded method 
# return by GetMethods
# For example (using PS 3.0 features):

$svnclient.gettype().getmethods()|? name -eq Update |
% {write-host "***`n"';$_} | % GetParameters

# Will list parameter sets for each overload of Update, each set separated by stars

# Alternatively use getmethod with appropriate parameters    
# GetMethod (link below) can be used to select correct overload without the 
# filtering above. The next to the last overload of GetMethod at the link is the one to use

# After obtaining correct overload, then call the Invoke method like this:
$correctOverload.Invoke( $svnclient, @($repopath, [ref] $SvnUpdateResult))

获取方法链接

于 2015-10-26T14:57:00.983 回答