如何调用使用Powershell的C#out参数的重载.NET函数?

时间:2012-12-19 18:42:47

标签: .net powershell reference overloading

我知道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() method做的那样:

  1. Update(ICollection(String)) - 以递归方式将指定路径更新为最新(HEAD)修订版
  2. Update(String) - 递归更新指向最新(HEAD)修订版
  3. 的路径
  4. Update(ICollection(String), SvnUpdateArgs) - 更新指定版本的指定路径
  5. Update(ICollection(String), SvnUpdateResult) - 以递归方式将指定路径更新为最新(HEAD)修订版
  6. Update(String, SvnUpdateArgs) - 递归更新指定的路径
  7. Update(String, SvnUpdateResult) - 递归更新指向最新(HEAD)修订版
  8. 的路径
  9. Update(ICollection(String), SvnUpdateArgs, SvnUpdateResult) - 更新指定版本的指定路径
  10. Update(String, SvnUpdateArgs, SvnUpdateResult) - 递归更新指向最新(HEAD)修订版
  11. 的路径

    但是,如果我们想将所有这些放在一起怎么办?例如,如果我想调用Update()的第6个版本,那个带有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投射到ref$update = [ref]$null。这会导致错误:'无法将“System.Management.Automation.PSReference”类型的“System.Management.Automation.PSReference”值转换为“SharpSvn.SvnUpdateResult”类型。'

    看起来像两次施法是问题 - 最终施法只是覆盖了第一次施法,他们互不补充。这是发生了什么?有没有办法投两次?还有另一种解决这个问题的方法吗?

    提前感谢您的帮助。

5 个答案:

答案 0 :(得分:1)

这似乎很难做对。

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

根据我构建的类似场景,使用PowerShell的当前版本(4.0),我认为这是有效的:

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

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

在我的PowerShell版本中,如果我将第二个参数设为$svnclient.Update,则重载似乎正确解析,该方法运行时没有错误,但是对象分配给&#34; out&#34;参数似乎丢失了。

即使[ref][SharpSvn.SvnUpdateResult]$update被声明为$repopath的类型安全,我们仍然需要在传递它时(按值)再次说[string]$repopath = "C:\path\to\localrepo"

答案 1 :(得分:1)

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

我为此问题创建了一个简单的repro,为PowerShell创建了filed an issue

答案 2 :(得分:0)

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

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)

答案 3 :(得分:0)

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

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
    })

答案 4 :(得分:0)

你可以做的几件事:

首先,$svnclient.update返回的结果是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))

GetMethod Link