例如,我有一个具有以下方法重载的.NET对象$m
:
PS C:UsersMe> $m.GetBody
OverloadDefinitions
-------------------
T GetBody[T]()
T GetBody[T](System.Runtime.Serialization.XmlObjectSerializer serializer)
如果我尝试调用无参数方法,我会得到:
PS C:UsersMe> $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应该更容易地使用泛型。显然,我需要以某种方式告诉它我想要返回的类型,但我无法弄清楚语法。
看起来您正在尝试调用泛型方法。
在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!")
请参阅这篇精彩的博客文章以获取更多信息和其他示例。
对于您的示例,您可以尝试:
$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.调用($nonGenericClass)
在对象实例上调用泛型方法:
$instance.GetType().GetMethod('MethodName').MakeGenericMethod([TargetType]).Invoke($instance, $parameters)
调用静态泛型方法(另请参阅在 PowerShell 中调用泛型静态方法):
[ClassType].GetMethod('MethodName').MakeGenericMethod([TargetType]).Invoke($null, $parameters)
请注意,当该方法还存在非泛型版本时,会遇到AmbiguousMatchException
(请参阅如何在 .NET 中使用 GetMethod 区分泛型和非泛型签名?)。然后使用GetMethods()
:
([ClassType].GetMethods() | where {$_.Name -eq "MethodName" -and $_.IsGenericMethod})[0].MakeGenericMethod([TargetType]).Invoke($null, $parameters)
(请注意,可能有多个方法与上述过滤器匹配,因此请确保对其进行调整以找到所需的方法。
提示:可以像这样编写复杂的泛型类型文本(请参阅 Powershell 中泛型类型的泛型类型):
[System.Collections.Generic.Dictionary[int,string[]]]
若要从 Powershell v3 调用具有重载的(无参数)泛型方法(如 OP 示例中所示),请使用 @Chad Carisch 提供的引用中的脚本 Invoke-GenericMethod.ps1,在 PowerShell 中调用非泛型类上的泛型方法。
它应该看起来像
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:ProjectsSPG2013MainScriptsInvoke-GenericMethod $serviceLocator GetInstance Microsoft.Practices.SharePoint.Common.Configuration.IConfigManager @()
$config.CanAccessFarmConfig
这是一个我还没有尝试过的替代脚本,但更新并正在积极维护,从PowerShell调用泛型方法。
更新:PowerShell (Core) 7.3+ 现在支持调用具有显式类型参数的泛型方法。
# PS v7.3+ only; using [string] as an example type argument.
$m.GetBody[string]()
- 请参阅概念性about_Calling_Generic_Methods帮助主题
PowerShell (Core) 7.2- 和 Windows PowerShell:
Marsze 的有用答案包含有关调用泛型方法的大量一般信息,但让我专门解决调用无参数方法的方面,如前所述:
正如问题中所暗示的:
- 在 PSv3+ 中,PowerShell 可以从传递给泛型方法的参数值(参数)推断类型,
- 根据定义,它不能使用无参数泛型方法,因为没有什么可以从中推断类型。
在 PowerShell (Core) 7.3 之前,PowerShell 以前没有语法允许你在此方案中显式指定类型。
在此类旧版本中,必须使用反射:
# 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
)上的类型实例化方法,没有参数(@()
,空数组)。