Skip to content

Commit 0a57021

Browse files
IISResetMedaxian-dbw
authored andcommitted
Flatten interface hierarchy when generating properties that implement interface properties (#8382)
`TypeBuilder.GetInterfaces()` returns only the interfaces that was explicitly passed to its constructor, so we need to flatten the interface hierarchy in order to properly support inherited interfaces.
1 parent c14d5dd commit 0a57021

2 files changed

Lines changed: 32 additions & 4 deletions

File tree

src/System.Management.Automation/engine/parser/PSType.cs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ private class DefineTypeHelper
272272
internal readonly TypeBuilder _staticHelpersTypeBuilder;
273273
private readonly Dictionary<string, PropertyMemberAst> _definedProperties;
274274
private readonly Dictionary<string, List<Tuple<FunctionMemberAst, Type[]>>> _definedMethods;
275+
private HashSet<Tuple<string, Type>> _interfaceProperties;
275276
internal readonly List<(string fieldName, IParameterMetadataProvider bodyAst, bool isStatic)> _fieldsToInitForMemberFunctions;
276277
private bool _baseClassHasDefaultCtor;
277278

@@ -442,15 +443,33 @@ private Type GetBaseTypes(Parser parser, TypeDefinitionAst typeDefinitionAst, ou
442443

443444
private bool ShouldImplementProperty(string name, Type type)
444445
{
445-
foreach (var interfaceType in _typeBuilder.GetInterfaces())
446+
if (_interfaceProperties == null)
446447
{
447-
if (interfaceType.GetProperty(name, type) != null)
448+
_interfaceProperties = new HashSet<Tuple<string, Type>>();
449+
var allInterfaces = new HashSet<Type>();
450+
451+
// TypeBuilder.GetInterfaces() returns only the interfaces that was explicitly passed to its constructor.
452+
// During compilation the interface hierarchy is flattened, so we only need to resolve one level of ancestral interfaces.
453+
foreach (var interfaceType in _typeBuilder.GetInterfaces())
454+
{
455+
foreach (var parentInterface in interfaceType.GetInterfaces())
456+
{
457+
allInterfaces.Add(parentInterface);
458+
}
459+
460+
allInterfaces.Add(interfaceType);
461+
}
462+
463+
foreach (var interfaceType in allInterfaces)
448464
{
449-
return true;
465+
foreach (var property in interfaceType.GetProperties())
466+
{
467+
_interfaceProperties.Add(Tuple.Create(property.Name, property.PropertyType));
468+
}
450469
}
451470
}
452471

453-
return false;
472+
return _interfaceProperties.Contains(Tuple.Create(name, type));
454473
}
455474

456475
public void DefineMembers()

test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ Describe 'Classes inheritance syntax' -Tags "CI" {
7171
$getter.Attributes -band [System.Reflection.MethodAttributes]::Virtual |Should -Be ([System.Reflection.MethodAttributes]::Virtual)
7272
}
7373

74+
It 'can implement inherited .NET interface properties' {
75+
Add-Type -TypeDefinition 'public interface IParent { int ParentInteger { get; set; } }
76+
public interface IChild : IParent { int ChildInteger { get; set; } }'
77+
$C1 = Invoke-Expression 'class ClassWithInheritedInterfaces : IChild { [int]$ParentInteger; [int]$ChildInteger } [ClassWithInheritedInterfaces]'
78+
$getter = $C1.GetMember('get_ParentInteger')
79+
$getter.ReturnType.FullName | Should -Be System.Int32
80+
$getter.Attributes -band [System.Reflection.MethodAttributes]::Virtual |Should -Be ([System.Reflection.MethodAttributes]::Virtual)
81+
}
82+
7483
It 'allows use of defined later type as a property type' {
7584
class A { static [B]$b }
7685
class B : A {}

0 commit comments

Comments
 (0)