Advertisement
Guest User

Justin Dearing

a guest
Mar 3rd, 2011
263
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ## Invoke-GenericMethod.ps1
  2. ## Invoke a generic method on a non-generic type:
  3. ##
  4. ## Usage:
  5. ##
  6. ##   ## Load the DLL that contains our class
  7. ##   [Reflection.Assembly]::LoadFile("c:\temp\GenericClass.dll")
  8. ##
  9. ##   ## Invoke a generic method on a non-generic instance
  10. ##   $nonGenericClass = New-Object NonGenericClass
  11. ##   Invoke-GenericMethod $nonGenericClass GenericMethod String "How are you?"
  12. ##
  13. ##   ## Including one with multiple arguments
  14. ##   Invoke-GenericMethod $nonGenericClass GenericMethod String ("How are you?",5)
  15. ##
  16. ##   ## Ivoke a generic static method on a type
  17. ##   Invoke-GenericMethod ([NonGenericClass]) GenericStaticMethod String "How are you?"
  18. ##
  19. param(
  20.     $instance = $(throw "Please provide an instance on which to invoke the generic method"),
  21.     [string] $methodName = $(throw "Please provide a method name to invoke"),
  22.     [string[]] $typeParameters = $(throw "Please specify the type parameters"),
  23.     [object[]] $methodParameters = $(throw "Please specify the method parameters")
  24.     )
  25. ## Determine if the types in $set1 match the types in $set2, replacing generic
  26. ## parameters in $set1 with the types in $genericTypes
  27. function ParameterTypesMatch([type[]] $set1, [type[]] $set2, [type[]] $genericTypes)
  28. {
  29.     $typeReplacementIndex = 0
  30.     $currentTypeIndex = 0
  31.     ## Exit if the set lengths are different
  32.     if($set1.Count -ne $set2.Count)
  33.     {
  34.         return $false
  35.     }
  36.     ## Go through each of the types in the first set
  37.     foreach($type in $set1)
  38.     {
  39.         ## If it is a generic parameter, then replace it with a type from
  40.         ## the $genericTypes list
  41.         if($type.IsGenericParameter)
  42.         {
  43.             $type = $genericTypes[$typeReplacementIndex]
  44.             $typeReplacementIndex++
  45.         }
  46.         ## Check that the current type (i.e.: the original type, or replacement
  47.         ## generic type) matches the type from $set2
  48.         if( $type -ne $set2[$currentTypeIndex] -and -not ($set2[$currentTypeIndex].IsSubclassOf($type)) )
  49.         {
  50.             return $false
  51.         }
  52.         $currentTypeIndex++
  53.     }
  54.     return $true
  55. }
  56. ## Convert the type parameters into actual types
  57. [type[]] $typedParameters = $typeParameters
  58. ## Determine the type that we will call the generic method on. Initially, assume
  59. ## that it is actually a type itself.
  60. $type = $instance
  61. ## If it is not, then it is a real object, and we can call its GetType() method
  62. if($instance -isnot "Type")
  63. {
  64.     $type = $instance.GetType()
  65. }
  66. ## Search for the method that:
  67. ##    - has the same name
  68. ##    - is public
  69. ##    - is a generic method
  70. ##    - has the same parameter types
  71. $methodCandidates = $type.GetMethods() | Where-Object {
  72.     $_.Name -eq $methodName -and
  73.     $_.IsPublic -and
  74.     $_.IsGenericMethod
  75. };
  76. foreach($method in $methodCandidates)
  77. {
  78.     $parameterTypes = @($method.GetParameters() | % { $_.ParameterType })
  79.     $methodParameterTypes = @($methodParameters | % { $_.GetType() })
  80.     if(ParameterTypesMatch $parameterTypes $methodParameterTypes $typedParameters)
  81.     {
  82.         ## Create a closed representation of it
  83.         $newMethod = $method.MakeGenericMethod($typedParameters)
  84.         ## Invoke the method
  85.         $newMethod.Invoke($instance, $methodParameters)
  86.         return
  87.     }
  88. }
  89. ## Return an error if we couldn't find that method
  90. throw "Could not find method $methodName"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement