2012-12-19 8 views
8

wiem, że PowerShell można wywołać kodu .NET, który może wyglądać następującoJak mogę wywołać przeciążoną funkcję .NET, która używa argumentu C# out z Powershell?

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

I wiem, że w przypadku C# ma out argumenty, PowerShell ma [ref] argumenty, które mogłyby wyglądać następująco:

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

I wiem, że w C# można przeciążać funkcje, jak biblioteka SharpSvn robi dla swoich SvnClient.Update() method:

  1. Update(ICollection(String)) - rekurencyjnie aktualizuje określone ścieżki do najnowszej (głowa) rewizji
  2. Update(String) - rekurencyjnie aktualizuje sciezki do najnowszej (głowa) rewizji
  3. Update(ICollection(String), SvnUpdateArgs) - Aktualizuje określone ścieżki do określonego rewizji
  4. Update(ICollection(String), SvnUpdateResult) - rekurencyjnie aktualizuje określone ścieżki do najnowszej (głowa) rewizji
  5. Update(String, SvnUpdateArgs) - rekurencyjnie aktualizuje sciezki
  6. Update(String, SvnUpdateResult) - rekurencyjnie aktualizuje sciezki do najnowszej (głowa) REVI sion
  7. Update(ICollection(String), SvnUpdateArgs, SvnUpdateResult) - Aktualizuje określone ścieżki do określonego rewizji
  8. Update(String, SvnUpdateArgs, SvnUpdateResult) - rekurencyjnie aktualizuje sciezki do najnowszej (głowa) rewizji

Ale co zrobić, jeśli chcemy umieścić to wszystko razem? Jeśli, powiedzmy, chcę wywołać 6. wersję Update(), która pobiera String i SvnUpdateResult, gdzie SvnUpdateResult jest obiektem C# out? Moim pierwszym instynktem było wypróbowanie czegoś takiego:

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 

OK, może muszę rzucić kłótnie?

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 

Ale to też nie działa. Inne rzeczy próbowałem:

  • odlewania $update jak [SharpSvn.SvnUpdateResult][ref] - czyli odwrócenie kolejności, że rzucam go. Powoduje to błąd, który stwierdza: "[ref] może być tylko ostatnim typem w sekwencji konwersji typu."
  • Przesyłanie od $update do SharpSvn.SvnUpdateResult przed użyciem: $update = [SharpSvn.SvnUpdateResult]$null. Powoduje to ten sam błąd "Wiele niejednoznacznych przeciążeń", który wystąpił powyżej
  • Przesyłanie od $update do ref przed użyciem: $update = [ref]$null. Powoduje to błąd: "Nie można przekonwertować wartości" System.Management.Automation.PSReference "typu" System.Management.Automation.PSReference ", aby wpisać" SharpSvn.SvnUpdateResult "."

Wygląda na to, że problem polega na rzucaniu go dwukrotnie - ostateczna obsada po prostu przesłania pierwszą obsadę, nie uzupełniają się nawzajem. Czy to się dzieje? Czy istnieje sposób na rzucenie czegoś dwa razy? Czy istnieje inny sposób obejścia tego problemu?

Z góry dziękuję za pomoc.

+0

Zauważyłem, że możesz sprawdzić przeładowane definicje za pomocą '$ svnclient.Update.OverloadedDefinitions', ale nie ma sposobu, aby wywołać je z tego, co widzę. –

+0

Jednym ze sposobów uzyskania wglądu w wewnętrzną pracę programu PowerShell polegającego na konwersji typu konwersji/podziału członków jest uruchomienie polecenia 'Trace-Command -Name All -Expression {$ svnclient.update ($ repopath, [ref] $ update)} -PSHost' i sprawdzenie, czy to ujawnia cokolwiek pożytecznego. –

+0

Zwraca ten sam komunikat "Wiele niejednoznacznych przeciążeń", niestety. –

Odpowiedz

0

To może nie być idealne rozwiązanie, ale można użyć opcji Add-Type i stworzyć bardziej przyjazny dla PowerShell typ, który otoczy aktualizację.

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) 
+0

Powoduje to błąd podobny do poniższego: 'Add-Type: c: \ Users \ autotester \ AppData \ Local \ Temp \ 89jqcyvc.0.cs (4): Nie można znaleźć nazwy typu lub przestrzeni nazw" SvnClient "(są brakuje ci dyrektywy użycia lub odwołania do zestawu?) '... Próbowałem dodać' przy użyciu SharpSvn; 'u góry definicji, ale daje podobny błąd o tym, że nie można znaleźć SharpSvn. Jestem pewien, że brakuje mi czegoś prostego ... Nie jestem zaznajomiony z C# w ogóle ani z tym, jak szczególnie współpracuje z nim PowerShell. Co ja robię źle? (I dziękuję za wskaźnik!) –

+0

Zobacz parametr Assemblies Add-Type's ReferencedAssembly. Będziesz musiał dodać zespół klienta SVN do powyższego polecenia Add-Type. Przepraszam za to! –

0

można po prostu użyć blok kodu dostępu i wynik (out) obiektów w tym bloku:

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

To wydaje się być dość trudne, aby uzyskać prawo.

Jaka jest wersja PowerShell? Czy powiązane są SvnUpdateArgs i SvnUpdateResult (tj. Jedna klasa pochodzi z drugiej)? Nie zakładam.

oparciu o podobnym scenariuszu I zbudowanego z obecnej wersji (4.0) z PowerShell, to działa, myślę:

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

Jednak mogę dostać tylko to, aby pracować z jednym z przeciążeniami !? Nie jestem pewien, czy jest to zbieg okoliczności, ale było to przeciążenie, które wymieniono jako pierwsze, gdy powiedziałem $svnclient.Update, aby zobaczyć definicje przeciążenia.

W mojej wersji PowerShell, jeśli podam drugi argument jako [ref][SharpSvn.SvnUpdateResult]$update, przeciążenie wydaje się być poprawnie rozwiązane, metoda działa bez błędu, ale obiekt przypisany do parametru "out" wydaje się być utracony.

Nawet jeśli $repopath zostanie zadeklarowany jako bezpieczny dla użytkownika jako [string]$repopath = "C:\path\to\localrepo", wydaje się, że musimy jeszcze powiedzieć [string]$repopath, kiedy go przekazamy (według wartości).

0

Kilka rzeczy można zrobić:

Pierwszy wynik zwracany przez $svnclient.update jest PSMethod. PSMethod ma metodę Invoke. Możesz spróbować go użyć.

Po drugie, jeśli to nie zadziała można użyć prawdziwej refleksji:

# 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

+0

@ micah-r-ledbetter Albo pisanie C# CmdLets, albo to rozwiązanie do refleksji wydaje się najlepszą opcją. Poinformuję zespół PowerShell o tym, dlaczego połączenie nie działa, ale wątpię, aby poprawka wkrótce pojawi się w PowerShell. Znalazłem problemy w powyższym rozwiązaniu (składnia invoke jest błędna). Jeśli jesteś zainteresowany poprawkami, aby powyższe działania zadziałały, odpowiedz ponownie. – TravisEz13

1

Tam zdaje się być problemem w PowerShell, gdy istnieje metoda, aby zadzwonić z zewnątrz parametrze klasy i innego przeciążenia o podobnym sygnaturze (klasa może być dowolną klasą tego podpisu).

Utworzono proste repro dla tego wydania i filed an issue dla PowerShell.

Powiązane problemy