定义构造函数签名的接口?

奇怪的是,这是我第一次碰到这个问题,但是:

你如何定义一个C#接口的构造函数?

编辑
有些人想要一个例子(这是一个自由时间的项目,所以是的,这是一个游戏)

IDrawable
+更新
+绘制

为了能够更新(检查屏幕边缘等),并绘制自己将始终需要一个GraphicsDeviceManager 。 所以我想确保对象有一个参考。 这将属于构造函数。

现在我写下来了,我想我在这里实现的是IObservableGraphicsDeviceManager应该采用IDrawable …看来要么我没有得到XNA框架,或框架不是很好。

编辑
在接口的上下文中,我对构造函数的定义似乎有些困惑。 一个接口确实不能实例化,所以不需要构造函数。 我想定义的是一个构造函数的签名。 完全像一个接口可以定义一个特定方法的签名,接口可以定义一个构造函数的签名。

正如已经注意到的,你不能在接口上有构造函数。 但是,由于这是在7年后谷歌这样一个高度排名的结果,我想我会在这里 – 特别是显示如何使用一个抽象的基类与您现有的接口,并可能减less重构的数量类似的情况在未来需要。 这个观点已经在一些评论中暗示了,但是我认为值得展示如何真正做到这一点。

所以你的主界面看起来像这样:

 public interface IDrawable { void Update(); void Draw(); } 

现在用你想要实现的构造函数创build一个抽象类。 实际上,从你写下原始问题的时候开始就可以使用,所以我们可以在这里得到一些幻想,并且在这种情况下使用generics,这样我们就可以将它适应于其他可能需要相同function但是具有不同构造器要求的接口:

 public abstract class MustInitialize<T> { public MustInitialize(T parameters) { } } 

现在您需要创build一个从IDrawable接口和MustInitialize抽象类inheritance的新类:

 public class Drawable : MustInitialize<GraphicsDeviceManager>, IDrawable { GraphicsDeviceManager _graphicsDeviceManager; public Drawable(GraphicsDeviceManager graphicsDeviceManager) : base (graphicsDeviceManager) { _graphicsDeviceManager = graphicsDeviceManager; } public void Update() { //use _graphicsDeviceManager here to do whatever } public void Draw() { //use _graphicsDeviceManager here to do whatever } } 

然后创build一个Drawable的实例,你很好走:

 IDrawable drawableService = new Drawable(myGraphicsDeviceManager); 

这里很酷的事情是,我们创build的新的Drawable类仍然像我们所期待的那样可以performance出来。

如果您需要将多个parameter passing给MustInitialize构造函数,则可以创build一个类,为您需要传入的所有字段定义属性。

你不能。 偶尔会有一些痛苦,但是无论如何你都不能用普通的技术来调用它。

在一篇博客文章中,我提出了一些静态接口 ,这些接口只能在genericstypes的约束条件下使用 – 但是可能非常方便,IMO。

关于如果你可以在一个接口中定义一个构造函数的一点,你将无法派生类:

 public class Foo : IParameterlessConstructor { public Foo() // As per the interface { } } public class Bar : Foo { // Yikes! We now don't have a parameterless constructor... public Bar(int x) { } } 

一个很晚的贡献,展示了接口构造函数的另一个问题。 (我select这个问题是因为它对问题有清晰的expression)。 假设我们可以有:

 interface IPerson { IPerson(string name); } interface ICustomer { ICustomer(DateTime registrationDate); } class Person : IPerson, ICustomer { Person(string name) { } Person(DateTime registrationDate) { } } 

按照惯例,“接口构造函数”的实现被types名称replace。

现在做一个实例:

 ICustomer a = new Person("Ernie"); 

我们是否会说遵守合同ICustomer

那又如何呢?

 interface ICustomer { ICustomer(string address); } 

你不能。

接口定义了其他对象实现的契约,因此没有需要初始化的状态。

如果你有一些状态需要被初始化,你应该考虑使用一个抽象基类。

创build一个定义构造函数的接口不可能的,但是可以定义一个强制types具有无参构造函数的接口,尽pipe这是一种使用generics的非常丑陋的语法…实际上我不太确定这是一个很好的编码模式。

 public interface IFoo<T> where T : new() { void SomeMethod(); } public class Foo : IFoo<Foo> { // This will not compile public Foo(int x) { } #region ITest<Test> Members public void SomeMethod() { throw new NotImplementedException(); } #endregion } 

另一方面,如果你想testing一个types是否有无参数的构造函数,你可以使用reflection来实现:

 public static class TypeHelper { public static bool HasParameterlessConstructor(Object o) { return HasParameterlessConstructor(o.GetType()); } public static bool HasParameterlessConstructor(Type t) { // Usage: HasParameterlessConstructor(typeof(SomeType)) return t.GetConstructor(new Type[0]) != null; } } 

希望这可以帮助。

我回头看这个问题,我心想,也许我们是以错误的方式解决这个问题的。 当涉及到定义一个具有特定参数的构造函数时,接口可能不会成为一种方式,但是(抽象的)基类是。

如果你在那里创build一个具有构造函数的基类,它接受你需要的参数,那么每个需要提供它的类都需要提供它。

 public abstract class Foo { protected Foo(SomeParameter x) { this.X = x; } public SomeParameter X { get; private set } } public class Bar : Foo // Bar inherits from Foo { public Bar() : base(new SomeParameter("etc...")) // Bar will need to supply the constructor param { } } 

通用工厂的方法似乎仍然是理想的。 你会知道工厂需要一个参数,而且恰恰会发生这些参数被传递给被实例化的对象的构造函数。

注意,这只是语法validation的伪代码,可能有一个运行时警告我在这里失踪:

 public interface IDrawableFactory { TDrawable GetDrawingObject<TDrawable>(GraphicsDeviceManager graphicsDeviceManager) where TDrawable: class, IDrawable, new(); } public class DrawableFactory : IDrawableFactory { public TDrawable GetDrawingObject<TDrawable>(GraphicsDeviceManager graphicsDeviceManager) where TDrawable : class, IDrawable, new() { return (TDrawable) Activator .CreateInstance(typeof(TDrawable), graphicsDeviceManager); } } public class Draw : IDrawable { //stub } public class Update : IDrawable { private readonly GraphicsDeviceManager _graphicsDeviceManager; public Update() { throw new NotImplementedException(); } public Update(GraphicsDeviceManager graphicsDeviceManager) { _graphicsDeviceManager = graphicsDeviceManager; } } public interface IDrawable { //stub } public class GraphicsDeviceManager { //stub } 

可能用法的一个例子:

  public void DoSomething() { var myUpdateObject = GetDrawingObject<Update>(new GraphicsDeviceManager()); var myDrawObject = GetDrawingObject<Draw>(null); } 

当然,你只需要通过工厂的创build实例来保证你总是有一个适当的初始化对象。 也许使用像AutoFac这样的dependency injection框架是有道理的; Update()可以向IoC容器询问新的GraphicsDeviceManager对象。

解决这个问题的一个办法就是把build筑分拆成一个单独的工厂。 例如,我有一个名为IQueueItem的抽象类,我需要一种将该对象转换为另一个对象(CloudQueueMessage)的方法。 所以在界面IQueueItem我有 –

 public interface IQueueItem { CloudQueueMessage ToMessage(); } 

现在,我还需要一种方法让我的实际队列类将CloudQueueMessage转换回IQueueItem – 即需要像IQueueItem objMessage = ItemType.FromMessage这样的静态构造。 相反,我定义了另一个接口IQueueFactory –

 public interface IQueueItemFactory<T> where T : IQueueItem { T FromMessage(CloudQueueMessage objMessage); } 

现在,我终于可以写我的generics队列类没有新的()约束,在我的情况是主要问题。

 public class AzureQueue<T> where T : IQueueItem { private IQueueItemFactory<T> _objFactory; public AzureQueue(IQueueItemFactory<T> objItemFactory) { _objFactory = objItemFactory; } public T GetNextItem(TimeSpan tsLease) { CloudQueueMessage objQueueMessage = _objQueue.GetMessage(tsLease); T objItem = _objFactory.FromMessage(objQueueMessage); return objItem; } } 

现在我可以创build一个满足我的标准的实例

  AzureQueue<Job> objJobQueue = new JobQueue(new JobItemFactory()) 

希望有一天能够帮助别人,显然很多内部代码已经被删除,试图展示问题和解决scheme

你可以用generics技巧来做到这一点,但是它仍然容易被Jon Skeet所写:

 public interface IHasDefaultConstructor<T> where T : IHasDefaultConstructor<T>, new() { } 

实现这个接口的类必须有无参数的构造函数:

 public class A : IHasDefaultConstructor<A> //Notice A as generic parameter { public A(int a) { } //compile time error } 

解决这个问题的一个方法是利用generics和new()约束。

您可以将其表示为一个工厂类/接口,而不是将您的构造函数表示为方法/函数。 如果在每个需要创build类的对象的调用站点上指定new()通用约束,则可以相应地传递构造函数参数。

对于你的IDrawable的例子:

 public interface IDrawable { void Update(); void Draw(); } public interface IDrawableConstructor<T> where T : IDrawable { T Construct(GraphicsDeviceManager manager); } public class Triangle : IDrawable { public GraphicsDeviceManager Manager { get; set; } public void Draw() { ... } public void Update() { ... } public Triangle(GraphicsDeviceManager manager) { Manager = manager; } } public TriangleConstructor : IDrawableConstructor<Triangle> { public Triangle Construct(GraphicsDeviceManager manager) { return new Triangle(manager); } } 

现在,当你使用它:

 public void SomeMethod<TBuilder>(GraphicsDeviceManager manager) where TBuilder: IDrawableConstructor<Triangle>, new() { // If we need to create a triangle Triangle triangle = new TBuilder().Construct(manager); // Do whatever with triangle } 

您甚至可以使用显式接口实现将所有创build方法集中在一个类中:

 public DrawableConstructor : IDrawableConstructor<Triangle>, IDrawableConstructor<Square>, IDrawableConstructor<Circle> { Triangle IDrawableConstructor<Triangle>.Construct(GraphicsDeviceManager manager) { return new Triangle(manager); } Square IDrawableConstructor<Square>.Construct(GraphicsDeviceManager manager) { return new Square(manager); } Circle IDrawableConstructor<Circle>.Construct(GraphicsDeviceManager manager) { return new Circle(manager); } } 

要使用它:

 public void SomeMethod<TBuilder, TShape>(GraphicsDeviceManager manager) where TBuilder: IDrawableConstructor<TShape>, new() { // If we need to create an arbitrary shape TShape shape = new TBuilder().Construct(manager); // Do whatever with the shape } 

另一种方法是使用lambdaexpression式作为初始值。 在调用层次结构的早期阶段,您将知道需要实例化哪些对象(即创build或获取对GraphicsDeviceManager对象的引用时)。 只要你有它,通过拉姆达

 () => new Triangle(manager) 

到后续的方法,以便他们知道如何创build一个三angular形。 如果你不能确定你需要的所有可能的方法,你总是可以创build一个使用reflection实现IDrawable的types的字典,并将上面显示的lambdaexpression式注册到一个字典中,这个字典可以存储在一个共享位置或者传递给进一步的函数调用

你没有。

构造函数是可以实现接口的类的一部分。 接口只是类必须实现的方法的合约。

如果可以在接口中定义构造函数,这将是非常有用的。

鉴于接口是必须以指定的方式使用的合同。 以下方法可能是一些可行的scheme:

 public interface IFoo { /// <summary> /// Initialize foo. /// </summary> /// <remarks> /// Classes that implement this interface must invoke this method from /// each of their constructors. /// </remarks> /// <exception cref="InvalidOperationException"> /// Thrown when instance has already been initialized. /// </exception> void Initialize(int a); } public class ConcreteFoo : IFoo { private bool _init = false; public int b; // Obviously in this case a default value could be used for the // constructor argument; using overloads for purpose of example public ConcreteFoo() { Initialize(42); } public ConcreteFoo(int a) { Initialize(a); } public void Initialize(int a) { if (_init) throw new InvalidOperationException(); _init = true; b = a; } } 

强制某种构造函数的一种方法是在接口中声明只有Getters ,这意味着实现类必须有一个方法,最好是一个构造函数,为其设置值( private )。

虽然不能在接口中定义构造函数签名,但我觉得值得一提的是,这可能是考虑抽象类的一个地方。 抽象类可以像接口一样定义未实现(抽象)方法签名,但也可以实现(具体)方法和构造函数。

缺点是,因为它是一种types,所以它不能用于任何一个接口可以的多inheritancetypes场景。

如果我正确地理解了OP,我们想要在GraphicsDeviceManager始终通过实现类来初始化的地方执行一个合同。 我有一个类似的问题,我正在寻找一个更好的解决scheme,但这是我能想到的最好的:

添加一个SetGraphicsDeviceManager(GraphicsDeviceManager gdo)到接口,这样的实现类将被迫写一个逻辑,这将需要从构造函数调用。