如何强制类实现构造函数?

时间:2017-10-28 08:52:10

标签: c# interface class-design abstract-class

我有一个界面static float speed = 30; // move speed outside method to not create it each frame. private void playerMovement() { if(Gdx.input.isKeyPressed(Input.Keys.W)){ body.setLinearVelocity(0f, speed); // removed Vector2(), it's not a good idea to cteate it each frame. }if(Gdx.input.isKeyPressed(Input.Keys.S)){ body.setLinearVelocity(0f, -speed); }if(Gdx.input.isKeyPressed(Input.Keys.A)){ body.setLinearVelocity(-speed, 0f); }if(Gdx.input.isKeyPressed(Input.Keys.D)){ body.setLinearVelocity(speed,0f); }if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.A)){ body.setLinearVelocity(-speed, speed); }if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.D)){ body.setLinearVelocity(speed, speed); }if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.A)){ body.setLinearVelocity(-speed, -speed); }if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.D)){ body.setLinearVelocity(speed, -speed); }else { body.setLinearVelocity(0f,0f); } }

IPopUp

我有几个实现:public interface IPopUp { bool IsCancelable {get;} void Show(); void Close(); Action MainAction{ get; } Action CancelAction{ get; } } IfoPopUpErrorPopUp

我正在使用LoadingPopUp实例

创建PopUps的实例
PopUpManager

我不知道如何强制 public class PopUpManager { public void ShowPopUp<T>(string texto) where T:IPopUp { ShowPopup (()=>(IPopUp)Activator.CreateInstance (typeof(T))); } public void ShowPopUp<T>(string texto,Action mainAction)where T:IPopUp { ShowPopup (()=>(IPopUp)Activator.CreateInstance (typeof(T), mainAction)); } public void ShowPopUp<T>(string texto,Action mainAction,Action cancelAction)where T:IPopUp { ShowPopup (()=>(IPopUp)Activator.CreateInstance (typeof(T), mainAction, cancelAction)); } private void ShowPopup(Func<IPopUp> factoryFunc) { if (PopUpShowed != null) { PopUpShowed.Close (); } IPopUp popUp = factoryFunc (); popUp.Show (); } } 实现来实现我在IPopUp中使用的3种构造函数。 抽象类不会起作用,因为它可以强制构造函数...... 有什么想法吗?

3 个答案:

答案 0 :(得分:1)

我最终通过重构类PopUpManager,因此需要工厂委托才能生成PopUpManager。 很清楚,实例化PopUps的责任来自于有很大意义的调用者。

PopUp

无论如何,我有兴趣知道哪种方法最好强制类实现一些构造函数。

答案 1 :(得分:1)

您已经找到了一个很好的解决方案。这里有一些关于强制类实现某些构造函数的其他见解。

可以通过界面完成吗?

C# language specification 5.0在第13章中定义了什么是接口:

  

接口定义合同。实现一个的类或结构   接口必须遵守其合同。接口可以继承   多个基接口,类或结构可以实现多个   接口。
接口可以包含方法,属性,事件和   索引。接口本身不提供实现   它定义的成员。界面只是指定了   必须由实现该类的类或结构提供的成员   接口

实例构造函数不是方法,不能是接口的一部分。这在13.2中明确提醒:

  

接口不能包含常量,字段,运算符,实例   构造函数,析构函数或类型,接口也不能包含   任何形式的静态成员。

有很多理由可以证明这种语言设计的选择,你可以在SO上找到一些额外的解释。另请注意,其他语言具有类似的约束。例如,Java声明“接口可能无法直接实例化。

可以用抽象类完成吗?

C#语言规范在10.1.1.1节中说明。那个:

  

abstract修饰符用于指示类是不完整的   并且它仅用作基类。 (...)抽象类不能直接实例化,在抽象类上使用new运算符是编译时错误。

简而言之,如果要在抽象类中定义三个不同的构造函数,派生类必须调用其中一个构造函数,但不对它们自己的构造函数赋予任何约束。请注意,此逻辑也适用于C ++或Java。

抽象类与其派生类的链接类似于实现{{1}的ShapeSquareRectangleCircle之间的链接}:Rectangle的构造参数可能与Circle的构造参数非常不同,因此Shape不能将约束放在其子元素的构造函数上。

可以用组合来完成吗?

您希望Shape实例化具有某些属性的PopupManager。不幸的是,您无法以安全的方式直接实例化IPopUpActivator.CreateInstance()可能会触发异常)。

为了确保安全,您可以强制IPopUp要求IPopUpMainAction的设置器,并添加构造函数约束(例如CancelAction)来制作确保可以毫无意外地创建实例,并更改对象以满足需要。

但在某些情况下,需要在施工时提供参数。在这种情况下,您可以考虑使用您选择的builder pattern或工厂方法。请注意,在允许具有静态成员的接口的语言中,您甚至可以在where T:IPopUp, new()接口中强制使用三个静态工厂方法。

答案 2 :(得分:0)

我有类似的问题。在我的例子中,具有特定属性[SpecialAttribute]的类需要具有无参数构造函数。

我在每次构建后添加了一个在CI服务器上运行的测试,其中搜索具有该属性的类,然后调用Activator.CreateInstance。如果由MissingMethodException s导致失败,则该测试“失败”并显示缺少无参数构造函数的类。

这并不完美,因为代码仍然可以编译。但是一个失败的自动化测试和明确的信息是向前迈出的重要一步。