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
|
#region member
|
||||||
|
|
||||||
internal virtual bool SiteBinderCanOptimize { get { return false; } }
|
internal virtual bool CanSiteBinderOptimize(MemberTypes typeToOperateOn) { return false; }
|
||||||
|
|
||||||
protected static IEnumerable<string> GetDotNetTypeNameHierarchy(Type type)
|
protected static IEnumerable<string> GetDotNetTypeNameHierarchy(Type type)
|
||||||
{
|
{
|
||||||
|
@ -3519,7 +3519,7 @@ namespace System.Management.Automation
|
||||||
|
|
||||||
#region member
|
#region member
|
||||||
|
|
||||||
internal override bool SiteBinderCanOptimize { get { return true; } }
|
internal override bool CanSiteBinderOptimize(MemberTypes typeToOperateOn) { return true; }
|
||||||
|
|
||||||
private static ConcurrentDictionary<Type, ConsolidatedString> s_typeToTypeNameDictionary =
|
private static ConcurrentDictionary<Type, ConsolidatedString> s_typeToTypeNameDictionary =
|
||||||
new ConcurrentDictionary<Type, ConsolidatedString>();
|
new ConcurrentDictionary<Type, ConsolidatedString>();
|
||||||
|
@ -4545,7 +4545,24 @@ namespace System.Management.Automation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal abstract class PropertyOnlyAdapter : DotNetAdapter
|
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)
|
protected override ConsolidatedString GetInternedTypeNameHierarchy(object obj)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5053,7 +5053,7 @@ namespace System.Management.Automation.Language
|
||||||
|
|
||||||
bool canOptimize;
|
bool canOptimize;
|
||||||
Type aliasConversionType;
|
Type aliasConversionType;
|
||||||
memberInfo = GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType);
|
memberInfo = GetPSMemberInfo(target, out restrictions, out canOptimize, out aliasConversionType, MemberTypes.Property);
|
||||||
|
|
||||||
if (!canOptimize)
|
if (!canOptimize)
|
||||||
{
|
{
|
||||||
|
@ -5415,8 +5415,8 @@ namespace System.Management.Automation.Language
|
||||||
return null;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5424,6 +5424,7 @@ namespace System.Management.Automation.Language
|
||||||
out BindingRestrictions restrictions,
|
out BindingRestrictions restrictions,
|
||||||
out bool canOptimize,
|
out bool canOptimize,
|
||||||
out Type aliasConversionType,
|
out Type aliasConversionType,
|
||||||
|
MemberTypes memberTypeToOperateOn,
|
||||||
HashSet<string> aliases = null,
|
HashSet<string> aliases = null,
|
||||||
List<BindingRestrictions> aliasRestrictions = null)
|
List<BindingRestrictions> aliasRestrictions = null)
|
||||||
{
|
{
|
||||||
|
@ -5493,7 +5494,7 @@ namespace System.Management.Automation.Language
|
||||||
var adapterSet = PSObject.GetMappedAdapter(value, typeTable);
|
var adapterSet = PSObject.GetMappedAdapter(value, typeTable);
|
||||||
if (memberInfo == null)
|
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.
|
// Don't bother looking for the member if we're not going to use it.
|
||||||
if (canOptimize)
|
if (canOptimize)
|
||||||
{
|
{
|
||||||
|
@ -5969,7 +5970,7 @@ namespace System.Management.Automation.Language
|
||||||
BindingRestrictions restrictions;
|
BindingRestrictions restrictions;
|
||||||
bool canOptimize;
|
bool canOptimize;
|
||||||
Type aliasConversionType;
|
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());
|
restrictions = restrictions.Merge(value.PSGetTypeRestriction());
|
||||||
|
|
||||||
|
@ -6464,7 +6465,7 @@ namespace System.Management.Automation.Language
|
||||||
BindingRestrictions restrictions;
|
BindingRestrictions restrictions;
|
||||||
bool canOptimize;
|
bool canOptimize;
|
||||||
Type aliasConversionType;
|
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()));
|
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
|
// 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