Fix 'PropertyOnlyAdapter' to allow calling base methods (#6394)
For a PropertyOnlyAdapter, the property may come from various sources, but methods, including parameterized properties, still come from DotNetAdapter. So, the binder can optimize on method calls for objects that map to a custom PropertyOnlyAdapter.
This commit is contained in:
parent
a099786cdc
commit
294def7b11
|
@ -46,7 +46,7 @@ namespace System.Management.Automation
|
|||
|
||||
#region member
|
||||
|
||||
internal virtual bool SiteBinderCanOptimize { get { return false; } }
|
||||
internal virtual bool CanSiteBinderOptimize(MemberTypes typeToOperateOn) { return false; }
|
||||
|
||||
protected static IEnumerable<string> GetDotNetTypeNameHierarchy(Type type)
|
||||
{
|
||||
|
@ -3519,7 +3519,7 @@ namespace System.Management.Automation
|
|||
|
||||
#region member
|
||||
|
||||
internal override bool SiteBinderCanOptimize { get { return true; } }
|
||||
internal override bool CanSiteBinderOptimize(MemberTypes typeToOperateOn) { return true; }
|
||||
|
||||
private static ConcurrentDictionary<Type, ConsolidatedString> s_typeToTypeNameDictionary =
|
||||
new ConcurrentDictionary<Type, ConsolidatedString>();
|
||||
|
@ -4545,7 +4545,24 @@ namespace System.Management.Automation
|
|||
/// </summary>
|
||||
internal abstract class PropertyOnlyAdapter : DotNetAdapter
|
||||
{
|
||||
internal override bool SiteBinderCanOptimize { get { return false; } }
|
||||
/// <summary>
|
||||
/// For a PropertyOnlyAdapter, the property may come from various sources,
|
||||
/// but methods, including parameterized properties, still come from DotNetAdapter.
|
||||
/// So, the binder can optimize on method calls for objects that map to a
|
||||
/// custom PropertyOnlyAdapter.
|
||||
/// </summary>
|
||||
internal override bool CanSiteBinderOptimize(MemberTypes typeToOperateOn)
|
||||
{
|
||||
switch (typeToOperateOn)
|
||||
{
|
||||
case MemberTypes.Property:
|
||||
return false;
|
||||
case MemberTypes.Method:
|
||||
return true;
|
||||
default:
|
||||
throw new InvalidOperationException("Should be unreachable. Update code if other member types need to be handled here.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override ConsolidatedString GetInternedTypeNameHierarchy(object obj)
|
||||
{
|
||||
|
|
|
@ -5053,7 +5053,7 @@ namespace System.Management.Automation.Language
|
|||
|
||||
bool canOptimize;
|
||||
Type aliasConversionType;
|
||||
memberInfo = GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType);
|
||||
memberInfo = GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType, MemberTypes.Property);
|
||||
|
||||
if (!canOptimize)
|
||||
{
|
||||
|
@ -5415,8 +5415,8 @@ namespace System.Management.Automation.Language
|
|||
return null;
|
||||
}
|
||||
|
||||
PSMemberInfo result = binder.GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType, aliases, aliasRestrictions);
|
||||
|
||||
PSMemberInfo result = binder.GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType,
|
||||
MemberTypes.Property, aliases, aliasRestrictions);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -5424,6 +5424,7 @@ namespace System.Management.Automation.Language
|
|||
out BindingRestrictions restrictions,
|
||||
out bool canOptimize,
|
||||
out Type aliasConversionType,
|
||||
MemberTypes memberTypeToOperateOn,
|
||||
HashSet<string> aliases = null,
|
||||
List<BindingRestrictions> aliasRestrictions = null)
|
||||
{
|
||||
|
@ -5493,7 +5494,7 @@ namespace System.Management.Automation.Language
|
|||
var adapterSet = PSObject.GetMappedAdapter(value, typeTable);
|
||||
if (memberInfo == null)
|
||||
{
|
||||
canOptimize = adapterSet.OriginalAdapter.SiteBinderCanOptimize;
|
||||
canOptimize = adapterSet.OriginalAdapter.CanSiteBinderOptimize(memberTypeToOperateOn);
|
||||
// Don't bother looking for the member if we're not going to use it.
|
||||
if (canOptimize)
|
||||
{
|
||||
|
@ -5969,7 +5970,7 @@ namespace System.Management.Automation.Language
|
|||
BindingRestrictions restrictions;
|
||||
bool canOptimize;
|
||||
Type aliasConversionType;
|
||||
memberInfo = _getMemberBinder.GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType);
|
||||
memberInfo = _getMemberBinder.GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType, MemberTypes.Property);
|
||||
|
||||
restrictions = restrictions.Merge(value.PSGetTypeRestriction());
|
||||
|
||||
|
@ -6464,7 +6465,7 @@ namespace System.Management.Automation.Language
|
|||
BindingRestrictions restrictions;
|
||||
bool canOptimize;
|
||||
Type aliasConversionType;
|
||||
var methodInfo = _getMemberBinder.GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType) as PSMethodInfo;
|
||||
var methodInfo = _getMemberBinder.GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType, MemberTypes.Method) as PSMethodInfo;
|
||||
restrictions = args.Aggregate(restrictions, (current, arg) => current.Merge(arg.PSGetMethodArgumentRestriction()));
|
||||
|
||||
// If the process has ever used ConstrainedLanguage, then we need to add the language mode
|
||||
|
|
|
@ -315,3 +315,49 @@ Describe "DataRow and DataRowView Adapter tests" -tags "CI" {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Base method call on object mapped to PropertyOnlyAdapter should work" -tags "CI" {
|
||||
It "Base method call on object of a subclass of 'XmlDocument' -- Add-Type" {
|
||||
$code =@'
|
||||
namespace BaseMethodCallTest.OnXmlDocument {
|
||||
public class Foo : System.Xml.XmlDocument {
|
||||
public string MyName { get; set; }
|
||||
public override void LoadXml(string content) {
|
||||
MyName = content;
|
||||
}
|
||||
}
|
||||
}
|
||||
'@
|
||||
try {
|
||||
$null = [BaseMethodCallTest.OnXmlDocument.Foo]
|
||||
} catch {
|
||||
Add-Type -TypeDefinition $code
|
||||
}
|
||||
|
||||
$foo = [BaseMethodCallTest.OnXmlDocument.Foo]::new()
|
||||
$foo.LoadXml('<test>bar</test>')
|
||||
$foo.MyName | Should -BeExactly '<test>bar</test>'
|
||||
$foo.ChildNodes.Count | Should -Be 0
|
||||
|
||||
([System.Xml.XmlDocument]$foo).LoadXml('<test>bar</test>')
|
||||
$foo.test | Should -BeExactly 'bar'
|
||||
$foo.ChildNodes.Count | Should -Be 1
|
||||
}
|
||||
|
||||
It "Base method call on object of a subclass of 'XmlDocument' -- PowerShell Class" {
|
||||
class XmlDocChild : System.Xml.XmlDocument {
|
||||
[string] $MyName
|
||||
[void] LoadXml([string]$content) {
|
||||
$this.MyName = $content
|
||||
# Try to call the base type's .LoadXml() method.
|
||||
([System.Xml.XmlDocument] $this).LoadXml($content)
|
||||
}
|
||||
}
|
||||
|
||||
$child = [XmlDocChild]::new()
|
||||
$child.LoadXml('<test>bar</test>')
|
||||
$child.MyName | Should -BeExactly '<test>bar</test>'
|
||||
$child.test | Should -BeExactly 'bar'
|
||||
$child.ChildNodes.Count | Should -Be 1
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue