Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell:继承的类调用Parent';s空构造函数,即使在传递对象时也是如此_Powershell_Class_Inheritance_Design Patterns_Constructor - Fatal编程技术网

Powershell:继承的类调用Parent';s空构造函数,即使在传递对象时也是如此

Powershell:继承的类调用Parent';s空构造函数,即使在传递对象时也是如此,powershell,class,inheritance,design-patterns,constructor,Powershell,Class,Inheritance,Design Patterns,Constructor,在powershell 5中,我遇到了一个奇怪的类继承问题 我想强制我们在安装过程中传递一个对象,比如[class]::new($mailbox\u object),我想通过使[class]::new()在关联对象未分配(比如子构造函数)时抛出一个错误来实现这一点 但是powershell在调用传递对象的子构造函数之前调用空的父构造函数,我不知道这是一个bug还是预期的,更重要的是,如何在创建时强制给我们一个对象 设计模式发言:我试图实现我所称的统一接口模式,这是一种门面模式,用于简化/统一与相

在powershell 5中,我遇到了一个奇怪的类继承问题

我想强制我们在安装过程中传递一个对象,比如
[class]::new($mailbox\u object)
,我想通过使
[class]::new()
在关联对象未分配(比如子构造函数)时抛出一个错误来实现这一点

但是powershell在调用传递对象的子构造函数之前调用空的父构造函数,我不知道这是一个bug还是预期的,更重要的是,如何在创建时强制给我们一个对象

设计模式发言:我试图实现我所称的统一接口模式,这是一种门面模式,用于简化/统一与相似但类型不同的对象的交互,其中使用策略模式选择这些对象的操作,并且在创建门面时由门面自动选择策略(目前尝试使用隐藏在立面内的不可见工厂)

IRL示例:尝试为Exchange邮箱/组对象创建统一接口,并实现MemberOf函数(以返回它是哪个组的成员)。但是邮箱和组使用不同的命令(尽管功能匹配),365和本地版本也使用不同的命令(get unifiedgroup而不是get distributiongroup)因此,为了清晰和可用性,我试图将复杂性隐藏在统一的外观后面

我愿意改变我的方法,特别是如果有更好的方法的话。请记住,至少会有以下类型的不同对象,每个对象都需要自己的.MemberOf()实现:
Interface\u Mailbox\u 365
Interface\u Mailbox\u OnPremises
Interface\u Group\u OnPremises
,我可能最终实现脱机和通用版本

下面的MRE,带有>的行是输出。因为我已经将其缩小到了接口创建的问题,所以我没有包括Facade或Factory,但是如果最终需要它们,我可以添加它们

class Interface_MailObject
{
    $MailObject = "Interface_MailObject class - initial"
    Interface_MailObject(){write-warning "Interface_MailObject::new() MailObject: {$($this.MailObject)}"}
    static [Interface_MailObject] Build($object)
    {
        if
            ($object -eq "Mailbox Standin")
            {return [Interface_Mailbox_365]::new($object)}
        else
            {throw("we don't reach here")}
    }
}
Class Interface_Mailbox : Interface_MailObject
{
    $MailObject = "Interface_Mailbox class - initial"
    Interface_Mailbox () {write-warning "Interface_Mailbox::new() MailObject: {$($this.MailObject)}"}
    Interface_Mailbox ($MailObject) {$this.MailObject = "Interface_Mailbox class - {$($MailObject)}"}
}
Class Interface_Mailbox_365 : Interface_Mailbox
{
    $MailObject = "Interface_Mailbox_365 class - initial"
    Interface_Mailbox_365 () {write-warning "Interface_Mailbox_365::new() MailObject: {$($this.MailObject)}"}
    Interface_Mailbox_365 ($MailObject) {$this.MailObject = "Interface_Mailbox_365 class - {$($MailObject)}"}
    [object[]] MemberOf(){throw("Interface_Mailbox_365.MemberOf TBD")}
}
[Interface_MailObject]::new("Mailbox Standin")|tee -va a

> WARNING: Interface_MailObject::new() MailObject: {Interface_Mailbox_365 class - initial}
> WARNING: Interface_Mailbox::new() MailObject: {Interface_Mailbox_365 class - initial}
> 
> MailObject                                     
> ----------                                     
> Interface_Mailbox_365 class - {Mailbox Standin}
请注意,尽管我们调用了
[Interface\u Mailbox\u 365]::new(“Mailbox Standin”)
powershell在运行我们调用的构造函数之前,先执行了祖父母的空构造函数,然后执行了父母的空构造函数

如果它们以另一种顺序执行,则可以。如果它们调用与相同参数数量和类型匹配的父构造函数,也可以

但这两者都不起作用,我不知道如何解决这个问题,而不使用一些奇怪的技巧来处理一个单例工厂,这似乎是对一些应该是常见需要的东西(在初始化过程中需要输入参数)的过度微观管理,所以我猜我忽略了一些东西

使用
child(object):base(object){}
来声明构造函数,而不是
child(object){}

感谢@Mathias R.Jessen帮我解决了这个问题。 起初,我认为我必须将Facade/Factory与模板分离,而不是让它们成为同一个类。不幸的是,这意味着我正在调用
[MailObject\u Interface]::Build($object)
,但没有返回
[MailObject\u Interface]
类型

在做了一些研究之后,我意识到Mathias所说的是一个子构造函数
child(object){}
被推断为意味着
child(object):base(){}
,你可以通过显式声明
child(object):base(object){}

用一个额外的片段来验证父母没有被直接调用,我成功了

Class MailObject_Interface
{
    [string] $MailObject

    MailObject_Interface ()
    {throw("You must call ::Build(`$object), because we return specialized types based on the mail object")}

    MailObject_Interface ($object) {[MailObject_Interface]::new()} # this triggers the error above

    MailObject_Interface ($object, $codephrase)
    {
        Write-Warning "calling MailObject_Interface::New($($object), $($codephrase)) {$($this.MailObject)}"
        # the Codephrase ensures 
        # either we're being called from one of our children,
        # or whomever calls us is aware of our internal workings and is taking responsibility for making sure we're handled correctly
        if
            ($codephrase -eq "Shazam!") 
            {$this.MailObject = $object}
        else
            {[MailObject_Interface]::new()} # this triggers the error above
    }
    # We run through ::Build instead of ::New because we want to return a child typed object rather than ourselves
    static [MailObject_Interface] Build($object)
    {
        if
            ($object -eq "Mailbox Standin")
            {return [Interface_Mailbox_365]::new($object)}
        else
            {throw("we don't reach here")}
    }
}
Class Interface_MailObject_Template : MailObject_Interface
{
    Interface_MailObject_Template ($object) : base ($object, "Shazam!") {Write-Warning "calling Interface_MailObject_Template::New($($object)) {$($this.MailObject)}"}
    [object[]] MemberOf(){throw(".MemberOf will be type+context specific")}
}
Class Interface_Mailbox : Interface_MailObject_Template
{
    Interface_Mailbox ($object) : base ($object) {Write-Warning "calling Interface_Mailbox::New($($object)) {$($this.MailObject)}"}
    [object[]] MemberOf(){throw("Mailbox.MemberOf will be context specific")}
}
Class Interface_Mailbox_365 : Interface_Mailbox
{
    Interface_Mailbox_365 ($object) : base ($object) {Write-Warning "calling Interface_Mailbox_365::New($($object)) {$($this.MailObject)}"}
    [object[]] MemberOf(){throw("Interface_Mailbox_365.MemberOf TBD")}
}

#\/ Rough Tests \/#

# should succeed
function Test_Correct()
    {
    Try
        {
        [MailObject_Interface]$a = [MailObject_Interface]::Build("Mailbox Standin")
        return "Succeded ($a)"
        }
    Catch
        {return "Failed"}
    }

# should fail
function Test_New_WithObject_MissingCodephrase()
    {
    Try
        {
        $a = [MailObject_Interface]::New("Mailbox Standin")
        return "Succeded: ($a)"
        }
    Catch
        {return "Failed"}
    }

# should fail
function Test_EmptyBuild()
    {
    Try
        {
        $a = [MailObject_Interface]::Build()
        return "Succeded: ($a)"
        }
    Catch
        {return "Failed"}
    }

# should fail
function Test_EmptyNew()
    {
    Try
        {
        $a = [MailObject_Interface]::New()
        return "Succeded: ($a)"
        }
    Catch
        {return "Failed"}
    }

"$(Test_Correct):`tTest_Correct (should have succeeded)"
"$(Test_New_WithObject_MissingCodephrase):`tTest_New_WithObject_MissingCodephrase (should have failed)"
"$(Test_EmptyBuild):`tTest_EmptyBuild (should have failed)"
"$(Test_EmptyNew):`tTest_EmptyNew (should have failed)"
这是测试结果

> WARNING: calling MailObject_Interface::New(Mailbox Standin, Shazam!) {}
> WARNING: calling Interface_MailObject_Template::New(Mailbox Standin) {Mailbox Standin}
> WARNING: calling Interface_Mailbox::New(Mailbox Standin) {Mailbox Standin}
> WARNING: calling Interface_Mailbox_365::New(Mailbox Standin) {Mailbox Standin}
> Succeded (Interface_Mailbox_365): Test_Correct (should have succeeded)
> Failed:   Test_New_WithObject_MissingCodephrase (should have failed)
> Failed:   Test_EmptyBuild (should have failed)
> Failed:   Test_EmptyNew (should have failed)

对于测试函数中不寻常的格式,我也很抱歉。我忘了将括号缩进转换为正常的标准,我使用了一种非标准的方法,我发现这种方法更具功能性,因为它使用空白框控制逻辑,使它更自然地跟随你在浏览时的周长行走。这是意料之中的。这很简单对象实例化在.NET中的工作方式-为类型层次结构中的每个父类型调用默认构造函数,以确保必要的分配(以及可选的分配)在所有membersOk中,是否有一种在初始化期间需要参数的正常方法?我知道您可以使用单个类来完成此操作,但当您添加继承时,它似乎会中断。您可以使用
base()
关键字指定特定的基类构造函数:
Interface\u Mailbox\u 365($MailObject):base($MailObject){…}
谢谢,但我不认为能够调用父方法会让我强制使用使用参数调用子构造函数。虽然如果没有继承构造函数,我可能可以通过将Facade/Factory与模板解耦来解决此问题。目前,我让Interface\u MailObject同时对另一个接口进行模板化s、 作为选择和返回特定接口的工厂,虽然我没有在最初的最小可复制示例中包括它,因为我认为这是未经调整添加的工厂组件,因为它看起来可能是相关的