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:
Mathias R. Jessen 2018-11-30 12:48:27 +01:00 committed by Ilya
parent 6e523f21eb
commit 950377faab
2 changed files with 26 additions and 0 deletions

View file

@ -434,6 +434,19 @@ namespace System.Management.Automation.Language
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()
{
// 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.
var getSetAttributes = Reflection.MethodAttributes.SpecialName | Reflection.MethodAttributes.HideBySig;
getSetAttributes |= propertyMemberAst.IsPublic ? Reflection.MethodAttributes.Public : Reflection.MethodAttributes.Private;
if (ShouldImplementProperty(propertyMemberAst.Name, type))
{
getSetAttributes |= Reflection.MethodAttributes.Virtual;
}
if (propertyMemberAst.IsStatic)
{
backingFieldAttributes |= FieldAttributes.Static;

View file

@ -63,6 +63,14 @@ Describe 'Classes inheritance syntax' -Tags "CI" {
[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' {
class A { static [B]$b }
class B : A {}