mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
[release/v7.4.2] Fix PowerShell class to support deriving from an abstract class with abstract properties (#21331) (#21422)
This commit is contained in:
@@ -276,7 +276,7 @@ namespace System.Management.Automation.Language
|
||||
internal readonly TypeBuilder _staticHelpersTypeBuilder;
|
||||
private readonly Dictionary<string, PropertyMemberAst> _definedProperties;
|
||||
private readonly Dictionary<string, List<Tuple<FunctionMemberAst, Type[]>>> _definedMethods;
|
||||
private HashSet<Tuple<string, Type>> _interfaceProperties;
|
||||
private HashSet<Tuple<string, Type>> _abstractProperties;
|
||||
internal readonly List<(string fieldName, IParameterMetadataProvider bodyAst, bool isStatic)> _fieldsToInitForMemberFunctions;
|
||||
private bool _baseClassHasDefaultCtor;
|
||||
|
||||
@@ -446,9 +446,9 @@ namespace System.Management.Automation.Language
|
||||
|
||||
private bool ShouldImplementProperty(string name, Type type)
|
||||
{
|
||||
if (_interfaceProperties == null)
|
||||
if (_abstractProperties == null)
|
||||
{
|
||||
_interfaceProperties = new HashSet<Tuple<string, Type>>();
|
||||
_abstractProperties = new HashSet<Tuple<string, Type>>();
|
||||
var allInterfaces = new HashSet<Type>();
|
||||
|
||||
// TypeBuilder.GetInterfaces() returns only the interfaces that was explicitly passed to its constructor.
|
||||
@@ -467,12 +467,23 @@ namespace System.Management.Automation.Language
|
||||
{
|
||||
foreach (var property in interfaceType.GetProperties())
|
||||
{
|
||||
_interfaceProperties.Add(Tuple.Create(property.Name, property.PropertyType));
|
||||
_abstractProperties.Add(Tuple.Create(property.Name, property.PropertyType));
|
||||
}
|
||||
}
|
||||
|
||||
if (_typeBuilder.BaseType.IsAbstract)
|
||||
{
|
||||
foreach (var property in _typeBuilder.BaseType.GetProperties())
|
||||
{
|
||||
if (property.GetAccessors().Any(m => m.IsAbstract))
|
||||
{
|
||||
_abstractProperties.Add(Tuple.Create(property.Name, property.PropertyType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _interfaceProperties.Contains(Tuple.Create(name, type));
|
||||
return _abstractProperties.Contains(Tuple.Create(name, type));
|
||||
}
|
||||
|
||||
public void DefineMembers()
|
||||
|
||||
@@ -628,3 +628,47 @@ class Derived : Base
|
||||
$sb.Invoke() | Should -Be 200
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'Base type has abstract properties' -Tags "CI" {
|
||||
It 'can derive from `FileSystemInfo`' {
|
||||
## FileSystemInfo has 3 abstract members that a derived type needs to implement
|
||||
## - public abstract bool Exists { get; }
|
||||
## - public abstract string Name { get; }
|
||||
## - public abstract void Delete ();
|
||||
|
||||
class myFileSystemInfo : System.IO.FileSystemInfo
|
||||
{
|
||||
[string] $Name
|
||||
[bool] $Exists
|
||||
|
||||
myFileSystemInfo([string]$path)
|
||||
{
|
||||
# ctor
|
||||
$this.Name = $path
|
||||
$this.Exists = $true
|
||||
}
|
||||
|
||||
[void] Delete()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
$myFile = [myFileSystemInfo]::new('Hello')
|
||||
$myFile.Name | Should -Be 'Hello'
|
||||
$myFile.Exists | Should -BeTrue
|
||||
}
|
||||
|
||||
It 'deriving from `FileSystemInfo` will fail when the abstract property `Exists` is not implemented' {
|
||||
$script = [scriptblock]::Create('class WillFail : System.IO.FileSystemInfo { [string] $Name }')
|
||||
$failure = $null
|
||||
try {
|
||||
& $script
|
||||
} catch {
|
||||
$failure = $_
|
||||
}
|
||||
|
||||
$failure | Should -Not -BeNullOrEmpty
|
||||
$failure.FullyQualifiedErrorId | Should -BeExactly "TypeCreationError"
|
||||
$failure.Exception.Message | Should -BeLike "*'get_Exists'*"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user