例如,我有一个.NET对象$m
,其中包含以下方法重载:
PS C:\Users\Me> $m.GetBody
OverloadDefinitions
-------------------
T GetBody[T]()
T GetBody[T](System.Runtime.Serialization.XmlObjectSerializer serializer)
如果我尝试调用无参数方法,我得到:
PS C:\Users\Me> $m.GetBody()
Cannot find an overload for "GetBody" and the argument count: "0".
At line:1 char:1
+ $m.GetBody()
+ ~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
我理解PowerShell v3.0应该更容易使用泛型。显然我需要告诉它我想要什么类型返回,但我无法弄清楚语法。
答案 0 :(得分:12)
看起来您正在尝试调用generic method。
在powershell中,可以通过以下方式完成:
$nonGenericClass = New-Object NonGenericClass
$method = [NonGenericClass].GetMethod("SimpleGenericMethod")
$gMethod = $method.MakeGenericMethod([string])
# replace [string] with the type you want to use for T.
$gMethod.Invoke($nonGenericClass, "Welcome!")
有关更多信息和其他示例,请参阅this精彩博文。
对于您的示例,您可以尝试:
$Source = @"
public class TestClass
{
public T Test<T>()
{
return default(T);
}
public int X;
}
"@
Add-Type -TypeDefinition $Source -Language CSharp
$obj = New-Object TestClass
$Type = $obj.GetType();
$m = $Type.GetMethod("Test")
$g = new-object system.Guid
$gType = $g.GetType()
$gm = $m.MakeGenericMethod($gType)
$out = $gm.Invoke( $obj, $null)
#$out will be the default GUID (all zeros)
这可以通过以下方式简化:
$Type.GetMethod("Test").MakeGenericMethod($gType).Invoke( $obj, $null)
这已经在powershell 2和powershell 3中进行了测试。
如果您有一个更详细的示例,了解您如何遇到这种通用方法,我将能够提供更多详细信息。我还没有看到任何微软cmdlet返回任何给你通用方法的东西。唯一出现的时间是使用c#或vb.net中的自定义对象或方法。
要在没有任何参数的情况下使用它,您可以仅使用第一个参数调用Invoke。 $ gMethod.Invoke($ nonGenericClass)
答案 1 :(得分:4)
在对象实例:
上调用泛型方法$instance.GetType().GetMethod('MethodName').MakeGenericMethod([TargetType]).Invoke($instance, $parameters)
调用静态泛型方法(另请参阅Calling generic static method in PowerShell):
[ClassType].GetMethod('MethodName').MakeGenericMethod([TargetType]).Invoke($null, $parameters)
请注意,当还存在非泛型版本的方法时,您会遇到AmbiguousMatchException
(请参阅How do I distinguish between generic and non generic signatures using GetMethod in .NET?)。然后使用GetMethods()
:
([ClassType].GetMethods() | where {$_.Name -eq "MethodName" -and $_.IsGenericMethod})[0].MakeGenericMethod([TargetType]).Invoke($null, $parameters)
(请注意,可能有多种方法与上述过滤器匹配,因此请务必调整以找到您需要的方法。)
提示:您可以编写这样的复杂泛型类型文字(参见Generic type of Generic Type in Powershell):
[System.Collections.Generic.Dictionary[int,string[]]]
答案 2 :(得分:2)
要从Powershell v3调用带有重载的(无参数)泛型方法,如OP示例所示,请使用@Chad Carisch提供的参考脚本Invoke-GenericMethod.ps1 {{ 3}}
应该看起来像
Invoke-GenericMethod $m GetBody T @()
这是我正在使用的经过验证的工作代码示例:
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Practices.ServiceLocation") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Practices.SharePoint.Common") | Out-Null
$serviceLocator = [Microsoft.Practices.SharePoint.Common.ServiceLocation.SharePointServiceLocator]::GetCurrent()
# Want the PowerShell equivalent of the following C#
# config = serviceLocator.GetInstance<IConfigManager>();
# Cannot find an overload for "GetInstance" and the argument count: "0".
#$config = $serviceLocator.GetInstance()
# Exception calling "GetMethod" with "1" argument(s): "Ambiguous match found."
#$config = $serviceLocator.GetType().GetMethod("GetInstance").MakeGenericMethod([IConfigManager]).Invoke($serviceLocator)
# Correct - using Invoke-GenericMethod
$config = C:\Projects\SPG2013\Main\Scripts\Invoke-GenericMethod $serviceLocator GetInstance Microsoft.Practices.SharePoint.Common.Configuration.IConfigManager @()
$config.CanAccessFarmConfig
这是一个我没有尝试但是更新的并且正在积极维护的替代脚本,Invoking Generic Methods on Non-Generic Classes in PowerShell。
答案 3 :(得分:1)
marsze's helpful answer包含有关调用泛型方法的大量常规信息,但让我着眼于如下要求专门调用无参数的方面:
问题提示:
从Windows PowerShell v5.1 / PowerShell Core v6.1.0开始, PowerShell具有 no 语法,该语法允许您在这种情况下显式指定类型。。>
但是,PowerShell Core 中有a suggestion on GitHub to enhance the syntax原则上已被批准,但是正在等待社区的实施。
目前,必须使用反射:
# Invoke $m.GetBody[T]() with [T] instantiated with type [decimal]
$m.GetType().GetMethod('GetBody', [type[]] @()).
MakeGenericMethod([decimal]).
Invoke($m, @())
.GetMethod('GetBody', [type[]] @())
明确地找到了.GetBody()
的无参数重载。
.MakeGenericMethod([decimal])
实例化示例类型为[decimal]
的方法。
.Invoke($m, @())
然后在不带参数($m
,空数组)的情况下调用输入对象(@()
)上类型实例化的方法。