Conditionally mark getter/setter implementations virtual in generated classes (#8303)
When implementing interfaces, PowerShell incorrectly produces non-virtual get/set methods for interface-defined properties. This commit adds a lookup method for interface-defined properties and marks get/set methods for properties with matching signatures virtual.
This commit is contained in:
parent
6e523f21eb
commit
950377faab
2 changed files with 26 additions and 0 deletions
|
@ -434,6 +434,19 @@ namespace System.Management.Automation.Language
|
||||||
return baseClass ?? typeof(object);
|
return baseClass ?? typeof(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ShouldImplementProperty(string name, Type type)
|
||||||
|
{
|
||||||
|
foreach (var interfaceType in _typeBuilder.GetInterfaces())
|
||||||
|
{
|
||||||
|
if (interfaceType.GetProperty(name, type) != null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void DefineMembers()
|
public void DefineMembers()
|
||||||
{
|
{
|
||||||
// If user didn't provide any instance ctors or static ctor we will generate default ctor or static ctor respectively.
|
// If user didn't provide any instance ctors or static ctor we will generate default ctor or static ctor respectively.
|
||||||
|
@ -576,6 +589,11 @@ namespace System.Management.Automation.Language
|
||||||
// The property set and property get methods require a special set of attributes.
|
// The property set and property get methods require a special set of attributes.
|
||||||
var getSetAttributes = Reflection.MethodAttributes.SpecialName | Reflection.MethodAttributes.HideBySig;
|
var getSetAttributes = Reflection.MethodAttributes.SpecialName | Reflection.MethodAttributes.HideBySig;
|
||||||
getSetAttributes |= propertyMemberAst.IsPublic ? Reflection.MethodAttributes.Public : Reflection.MethodAttributes.Private;
|
getSetAttributes |= propertyMemberAst.IsPublic ? Reflection.MethodAttributes.Public : Reflection.MethodAttributes.Private;
|
||||||
|
if (ShouldImplementProperty(propertyMemberAst.Name, type))
|
||||||
|
{
|
||||||
|
getSetAttributes |= Reflection.MethodAttributes.Virtual;
|
||||||
|
}
|
||||||
|
|
||||||
if (propertyMemberAst.IsStatic)
|
if (propertyMemberAst.IsStatic)
|
||||||
{
|
{
|
||||||
backingFieldAttributes |= FieldAttributes.Static;
|
backingFieldAttributes |= FieldAttributes.Static;
|
||||||
|
|
|
@ -63,6 +63,14 @@ Describe 'Classes inheritance syntax' -Tags "CI" {
|
||||||
[MyComparable].GetInterface("System.IComparable") | Should -Not -BeNullOrEmpty
|
[MyComparable].GetInterface("System.IComparable") | Should -Not -BeNullOrEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It 'can implement .NET interface properties' {
|
||||||
|
Add-Type -TypeDefinition 'public interface InterfaceWithProperty { int Integer { get; set; } }'
|
||||||
|
$C1 = Invoke-Expression 'class ClassWithInterfaceProperty : InterfaceWithProperty { [int]$Integer } [ClassWithInterfaceProperty]::new()'
|
||||||
|
$getter = $C1.GetType().GetMember('get_Integer')
|
||||||
|
$getter.ReturnType.FullName | Should -Be System.Int32
|
||||||
|
$getter.Attributes -band [System.Reflection.MethodAttributes]::Virtual |Should -Be ([System.Reflection.MethodAttributes]::Virtual)
|
||||||
|
}
|
||||||
|
|
||||||
It 'allows use of defined later type as a property type' {
|
It 'allows use of defined later type as a property type' {
|
||||||
class A { static [B]$b }
|
class A { static [B]$b }
|
||||||
class B : A {}
|
class B : A {}
|
||||||
|
|
Loading…
Reference in a new issue