Powershell类继承行为
我正试图利用PowerShell的继承来创建一个从现有类继承的类,但没有看到基于该类的预期行为 下面是一个突出问题的简单示例:Powershell类继承行为,powershell,class,inheritance,Powershell,Class,Inheritance,我正试图利用PowerShell的继承来创建一个从现有类继承的类,但没有看到基于该类的预期行为 下面是一个突出问题的简单示例: class child : System.Xml.XmlDocument { [String] ToString(){ return 'ChildString' } [void] LoadXml([string]$content) { Write-Host 'LoadXml' ([System.X
class child : System.Xml.XmlDocument {
[String] ToString(){
return 'ChildString'
}
[void] LoadXml([string]$content) {
Write-Host 'LoadXml'
([System.Xml.XmlDocument]$this).LoadXml($content)
}
}
如果我跑
Write-Host 'XMLDocument Object'
$xml=New-Object xml
$xml.ToString()
Write-Host 'Inherited Object'
$child=New-Object child
$child.ToString()
控制台输出为
XMLDocument Object
#document
Inherited Object
#document
指示未使用子类的ToString()
方法
另一方面,如果调用$child.LoadXml('Hello')
,则得到无限递归,这意味着对父对象的调用在该方法中失败
根据我所能找到的,我不希望这些方法会以这种方式运行,我希望有人能帮助我理解我所缺少的东西。我通常更习惯Python;然而,出于安全原因,我不能用另一种编程语言实现这段代码(我不能在要运行的计算机上安装软件)
谢谢
以下是
$PSversionTable.PSVersion
的结果,以供参考:
Major Minor Build Revision
----- ----- ----- --------
5 1 15063 909
在这两种情况下,对
ToString()
的调用都会被附加到其共同祖先System.Xml.XmlNode
的其他类型数据覆盖:
PS C:\> Get-TypeData -TypeName System.Xml.XmlNode
TypeName Members
-------- -------
System.Xml.XmlNode {[ToString, System.Management.Automation.Runspaces.CodeMethodData]}
您可以使用Remove TypeData
在运行时删除它:
Remove-TypeData -TypeName System.Xml.XmlNode
您现在应该看到您的子对象调用自己的方法,以及从系统继承的对象调用XmlDocument
对象调用ToString()
XMLDocument Object
System.Xml.XmlDocument
Inherited Object
ChildString
解释并解决隐藏的.ToString()
方法的问题
尽管该行为可能是模糊的,但它似乎是经过设计的:PowerShell允许自定义.NET类型,即使在派生类中也优先于此类自定义
相比之下,无法从.LoadXml()
方法调用基类方法闻起来像是一个bug,,[至少在PowerShell Core v6.1.0中已修复],听起来像
这里有一个解决方案,非常感谢地改编自:
这真的很有趣,解决了我99%的问题。我肯定得多研究一下TypeData。谢谢@谢谢!虽然令人恼火,但我相信这个成员决议顺序对ETS的行为至关重要。我在原始问题中看到的唯一错误是LoadXml
这件事。我发布了一个关于LoadXml
调用自身而不是基类的问题:出于我的目的,我可以利用LoadXml函数四处走动,当我测试它时,它的行为方式非常令人惊讶。再加上其他的行为,我觉得我快要疯了。无论如何,我测试了这个变通方法,它确实解决了问题。我希望我能把两个答案都标为已接受。谢谢
class child : System.Xml.XmlDocument {
[void] LoadXml([string]$content) {
Write-Host 'LoadXml'
# Get a function pointer to the base class method...
$funcPtr = [System.Xml.XmlDocument].GetMethod('LoadXml', [string]).MethodHandle.GetFunctionPointer()
# ...and invoke it with this instance.
[Activator]::CreateInstance([Action[string]], $this, $funcPtr).Invoke($content)
}
}