在基础构造函数中使用'this'?

时间:2012-02-26 06:11:04

标签: c# inheritance constructor this base

我正在开发一个涉及大量接口和继承的项目,这些项目开始变得有点棘手,现在我遇到了一个问题。

我有一个抽象类State,它将Game对象作为构造函数参数。在我的Game类的构造函数中,它接受一个State。这个想法是,当从抽象基类Game类继承时,在调用基类的构造函数时,你给它一个初始的State对象。但是,这个State对象与您正在创建它的游戏相同。代码如下所示:

public class PushGame : ManiaGame
{
     public PushGame() :
          base(GamePlatform.Windows, new PlayState(this), 60)
     {
     }
}

然而,这不起作用。我只能假设因为'this'关键字在构造函数开始执行之后才可用。试图在基类的构造函数中使用它显然不起作用。那么对我来说最好的解决方法是什么呢?我的计划B是从Game类的构造函数中删除State参数,然后在构造函数代码中设置状态。

是否有更容易,更少侵入性的方法?

5 个答案:

答案 0 :(得分:8)

显然,ManiaGame类总是使用PlayState类型的对象,因此您可以在ManiaGame级别移动创建:

public class PushGame : ManiaGame
{
     public PushGame() : base()
     {
     }

}

public class ManiaGame
{
    PlayState ps;   
    public ManiaGame() {
        ps = new PlayState(this);
    }
}

如果你想要更具体的PlayState类..

public class PushGame : ManiaGame
{
     public PushGame() : base()
     {
     }
     protected override PlayState CreatePlayState()
     {
        return new PushGamePlayState(this);
     }
}

public class ManiaGame
{
    PlayState ps;   
    public ManiaGame() {
          ps = CreatePlayState();
    }
    protected virtual PlayState CreatePlayState()
    {
        return new PlayState(this);
    }
}

public class PlayState
{
   public PlayState(ManiaGame mg) {}
}


public class PushGamePlayState : PlayState
{
   public PushGamePlayState(ManiaGame mg) : base(mg){}
}

答案 1 :(得分:1)

来自C# Language Specification

  

实例构造函数初始值设定项无法访问正在创建的实例。因此,在构造函数初始化程序的参数表达式中引用它是一个编译时错误,因为参数表达式通过simple_name引用任何实例成员的编译时错误。

即。 this只能用于在构造函数初始值设定项的上下文中引用另一个构造函数,因为在构造完成之前,对当前对象实例的引用将不可用。

即。 this只能在构造函数执行之前用作作用域关键字:

    : this("ParameterForAnotherConstructor")

但是它不能作为类实例的引用,因为它还没有完成构造

    : base(this) // Keyword this is not available in this context

显然我们不能从构造函数初始化程序中调用任何实例方法

    : base(GetThis()) // Object reference is required

要解决OP的问题,考虑到ManiaPlayState(或ManiaGame的子类之间的双向耦合,对基类ManiaGame类的更改似乎是不可避免的,例如PushGame)。有许多模式可用于解耦这样的紧密依赖,例如Dependency Inversion Principal(即抽象类之间的耦合)或Observer模式 - (两个类之一引发事件或允许回调挂钩(例如,委托或Action s),允许第二类“观察”状态变化,而不需要它们之间的硬耦合。

有一个类似的Stack Overflow问题, Keyword 'this' (Me) is not available calling the base constructor ,其解决方法类似于您的建议。

答案 2 :(得分:1)

如果使用的State实现取决于具体的Game类,那么我将在子State类的构造函数内创建Game的新实例( PushGame)并通过State属性访问基类中的abstract

public class PushGame : ManiaGame
{
    private readonly PlayState gamePlayState;

    public PushGame() : base()
    {
        gamePlayState = new PlayState(this);
    }

    protected override State GamePlayState
    {
        get { return gamePlayState; }
    }
}

public abstract class ManiaGame
{
    protected abstract State GamePlayState { get; }
}

public class State
{
    public State(ManiaGame mg) { }
}


public class PlayState : State
{
    public PlayState(ManiaGame mg) : base(mg) { }
}

答案 3 :(得分:0)

您的设计是否区分游戏(步步高)和正在进行的游戏(步步高游戏)?如果你想尝试混合这两个概念,那么我建议你分别对它们进行建模。例如,西洋双陆棋和西洋双陆棋。

答案 4 :(得分:0)

当尝试通过this将已实现接口的具体实例传递给基本构造函数时,我遇到了这个问题。

要解决此问题,我只是在基类上实现了一个抽象方法,该方法获取了我要查找的实例:

public abstract class BaseClass
{
    ...

    protected abstract IMyInterface GetInterface();

    ...
}

public class DerivedClass : BaseClass, IMyInterface
{
    ...

    protected override IMyInterface GetInterface()
    {
        return this;
    }

    ...
}

然后在我的基类代码中,您可以使用GetInterface(或所需的任何类型)来获取实例:

public abstract class BaseClass
{
    public void Foo()
    {
        GetInterface().DoSomething();
    }
}