Reputation: 171
I have been unable to work with more than one custom attribute (decorator) on PowerShell 5.0 class method. In C#, I'm able do to following:
public class SomeAttribute : Attribute {
public string Text { get; set; }
}
public class OtherAttribute : Attribute {
public string Text { get; set; }
}
public class MyClass {
[SomeAttribute(Text = "sometext")]
[OtherAttribute(Text = "othertext")]
public void MyMethod() {
// ...
}
}
and then somewhere else call
object[] customAttributes = typeof(MyClass).GetMethod("MyMethod").GetCustomAttributes(false);
which gives me an array of all custom attributes associated to the method without any problems.
In PowerShell 5.0, I'm trying to use analogically:
class SomeAttribute : Attribute {
[string]$Text
}
class OtherAttribute : Attribute {
[string]$Text
}
class MyClass {
[SomeAttribute(Text="sometext")]
[OtherAttribute(Text="othertext")]
MyMethod() {
# ...
}
}
which seems to be the proper syntax as PowerShell happily accepts it. But listing the attributes via
[MyClass].GetMethod("MyMethod").GetCustomAttributes($false)
returns following error:
Exception calling "GetCustomAttributes" with "1" argument(s): "Could not load type 'OtherAttribute' from assembly '⧹powershell, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'."
At line:1 char:1
+ [MyClass].GetMethod("MyMethod").GetCustomAttributes($false)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : TypeLoadException
and
[MyClass].GetMethod("MyMethod").CustomAttributes
simply returns $null
.
However when I use only one custom attribute, everything works as expected and the attribute is correctly returned using the snippets above.
How do I properly define multiple custom attributes for PowerShell 5.0 class method?
Let's assume only the first custom attribute from the original question.
class SomeAttribute : Attribute {
[string]$Text
}
class MyClass {
[SomeAttribute(Text="sometext")]
MyMethod() {
# ...
}
}
Then
[MyClass].GetMethod("MyMethod").GetCustomAttributes($false)
gives following output
Text TypeId
---- ------
sometext SomeAttribute
and
[MyClass].GetMethod("MyMethod").CustomAttributes
gives following output
AttributeType Constructor ConstructorArguments NamedArguments
------------- ----------- -------------------- --------------
SomeAttribute Void .ctor() {} {Text = "sometext"}
Which leads me to believe that one attribute indeed works as expected.
Upvotes: 4
Views: 1118
Reputation: 22132
It seems that PowerShell (.NET, IMHO) have troubles referencing two different assemblies with same full name (something tell me, that it is not possible in .NET).
PS> class A {}
PS> class B {}
PS> [A].Assembly -eq [B].Assembly
False
PS> [A].Assembly.FullName -eq [B].Assembly.FullName
True
PS> class CA { [A] $A }; class CB { [B] $B }
PS> [CA]::new().A #work fine
PS> [CB]::new().B #error
Solution would be to define classes A
and B
in the same command, this would put them in the same generated assembly:
PS> class A {}; class B {}
PS> [A].Assembly -eq [B].Assembly
True
PS> class CA { [A] $A }; class CB { [B] $B }
PS> [CA]::new().A #work fine
PS> [CB]::new().B #work fine
So, this work fine for me:
PS> class SomeAttribute : Attribute {
>>> [string]$Text
>>> }
>>> class OtherAttribute : Attribute {
>>> [string]$Text
>>> }
PS> class MyClass {
>>> [SomeAttribute(Text="sometext")]
>>> [OtherAttribute(Text="othertext")]
>>> MyMethod() {
>>> # ...
>>> }
>>> }
PS> [MyClass].GetMethod("MyMethod").GetCustomAttributes($false)
Text TypeId
---- ------
sometext SomeAttribute
othertext OtherAttribute
Other solution would be to not define classes in interactive session but in script files. In that case, obfuscated file name will be part of generated assembly name, thus you will not have this trouble even when attributes defines in different script files.
Upvotes: 2
Reputation: 36738
I am skeptical that you really got the results you expected even using just one custom attribute. The reason is that methods do not support attributes, at least that I have found. A method supports an optional return type that, in PowerShell, happens to look just like an attribute. That is you can define a method returning void...
MyMethod() {
$foo = 5
}
or a method returning something (like an int in this case)...
[int] MyMethod() {
$foo = 5
return $foo
}
(I'm hoping that someone can prove me wrong, though, and show that PowerShell classes do support attributes!)
Upvotes: 0