很奇怪,这是我第一次遇到这个问题,但是:

如何在c#接口中定义构造函数?

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

IDrawable +更新 +画

为了能够更新(检查屏幕边缘等)和绘制本身,它总是需要一个GraphicsDeviceManager。我想确保对象有一个指向它的引用。这将属于构造函数。

现在我把这个写下来了,我想我在这里实现的是IObservable GraphicsDeviceManager应该采用IDrawable。 似乎不是我没有理解XNA框架,就是这个框架没有考虑得很好。

编辑 我在接口上下文中对构造函数的定义似乎有些混乱。接口确实不能被实例化,因此不需要构造函数。我想定义的是构造函数的签名。就像接口可以定义某个方法的签名一样,接口也可以定义构造函数的签名。


当前回答

我用下面的图案使它防弹。

A developer who derives his class from the base can't accidentally create a public accessible constructor The final class developer are forced to go through the common create method Everything is type-safe, no castings are required It's 100% flexible and can be reused everywhere, where you can define your own base class. Try it out you can't break it without making modifications to the base classes (except if you define an obsolete flag without error flag set to true, but even then you end up with a warning) public abstract class Base<TSelf, TParameter> where TSelf : Base<TSelf, TParameter>, new() { protected const string FactoryMessage = "Use YourClass.Create(...) instead"; public static TSelf Create(TParameter parameter) { var me = new TSelf(); me.Initialize(parameter); return me; } [Obsolete(FactoryMessage, true)] protected Base() { } protected virtual void Initialize(TParameter parameter) { } } public abstract class BaseWithConfig<TSelf, TConfig>: Base<TSelf, TConfig> where TSelf : BaseWithConfig<TSelf, TConfig>, new() { public TConfig Config { get; private set; } [Obsolete(FactoryMessage, true)] protected BaseWithConfig() { } protected override void Initialize(TConfig parameter) { this.Config = parameter; } } public class MyService : BaseWithConfig<MyService, (string UserName, string Password)> { [Obsolete(FactoryMessage, true)] public MyService() { } } public class Person : Base<Person, (string FirstName, string LastName)> { [Obsolete(FactoryMessage,true)] public Person() { } protected override void Initialize((string FirstName, string LastName) parameter) { this.FirstName = parameter.FirstName; this.LastName = parameter.LastName; } public string LastName { get; private set; } public string FirstName { get; private set; } } [Test] public void FactoryTest() { var notInitilaizedPerson = new Person(); // doesn't compile because of the obsolete attribute. Person max = Person.Create(("Max", "Mustermann")); Assert.AreEqual("Max",max.FirstName); var service = MyService.Create(("MyUser", "MyPassword")); Assert.AreEqual("MyUser", service.Config.UserName); }

编辑: 这是一个基于你的绘图示例的例子,它甚至强制了接口抽象

        public abstract class BaseWithAbstraction<TSelf, TInterface, TParameter>
        where TSelf : BaseWithAbstraction<TSelf, TInterface, TParameter>, TInterface, new()
    {
        [Obsolete(FactoryMessage, true)]
        protected BaseWithAbstraction()
        {
        }

        protected const string FactoryMessage = "Use YourClass.Create(...) instead";
        public static TInterface Create(TParameter parameter)
        {
            var me = new TSelf();
            me.Initialize(parameter);

            return me;
        }

        protected virtual void Initialize(TParameter parameter)
        {

        }
    }



    public abstract class BaseWithParameter<TSelf, TInterface, TParameter> : BaseWithAbstraction<TSelf, TInterface, TParameter>
        where TSelf : BaseWithParameter<TSelf, TInterface, TParameter>, TInterface, new()
    {
        protected TParameter Parameter { get; private set; }

        [Obsolete(FactoryMessage, true)]
        protected BaseWithParameter()
        {
        }
        protected sealed override void Initialize(TParameter parameter)
        {
            this.Parameter = parameter;
            this.OnAfterInitialize(parameter);
        }

        protected virtual void OnAfterInitialize(TParameter parameter)
        {
        }
    }


    public class GraphicsDeviceManager
    {

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

    internal abstract class Drawable<TSelf> : BaseWithParameter<TSelf, IDrawable, GraphicsDeviceManager>, IDrawable 
        where TSelf : Drawable<TSelf>, IDrawable, new()
    {
        [Obsolete(FactoryMessage, true)]
        protected Drawable()
        {
        }

        public abstract void Update();
        public abstract void Draw();
    }

    internal class Rectangle : Drawable<Rectangle>
    {
        [Obsolete(FactoryMessage, true)]
        public Rectangle()
        {
        }

        public override void Update()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }

        public override void Draw()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }
    }
    internal class Circle : Drawable<Circle>
    {
        [Obsolete(FactoryMessage, true)]
        public Circle()
        {
        }

        public override void Update()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }

        public override void Draw()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }
    }


    [Test]
    public void FactoryTest()
    {
        // doesn't compile because interface abstraction is enforced.
        Rectangle rectangle = Rectangle.Create(new GraphicsDeviceManager());

        // you get only the IDrawable returned.
        IDrawable service = Circle.Create(new GraphicsDeviceManager());
    }

其他回答

我用下面的图案使它防弹。

A developer who derives his class from the base can't accidentally create a public accessible constructor The final class developer are forced to go through the common create method Everything is type-safe, no castings are required It's 100% flexible and can be reused everywhere, where you can define your own base class. Try it out you can't break it without making modifications to the base classes (except if you define an obsolete flag without error flag set to true, but even then you end up with a warning) public abstract class Base<TSelf, TParameter> where TSelf : Base<TSelf, TParameter>, new() { protected const string FactoryMessage = "Use YourClass.Create(...) instead"; public static TSelf Create(TParameter parameter) { var me = new TSelf(); me.Initialize(parameter); return me; } [Obsolete(FactoryMessage, true)] protected Base() { } protected virtual void Initialize(TParameter parameter) { } } public abstract class BaseWithConfig<TSelf, TConfig>: Base<TSelf, TConfig> where TSelf : BaseWithConfig<TSelf, TConfig>, new() { public TConfig Config { get; private set; } [Obsolete(FactoryMessage, true)] protected BaseWithConfig() { } protected override void Initialize(TConfig parameter) { this.Config = parameter; } } public class MyService : BaseWithConfig<MyService, (string UserName, string Password)> { [Obsolete(FactoryMessage, true)] public MyService() { } } public class Person : Base<Person, (string FirstName, string LastName)> { [Obsolete(FactoryMessage,true)] public Person() { } protected override void Initialize((string FirstName, string LastName) parameter) { this.FirstName = parameter.FirstName; this.LastName = parameter.LastName; } public string LastName { get; private set; } public string FirstName { get; private set; } } [Test] public void FactoryTest() { var notInitilaizedPerson = new Person(); // doesn't compile because of the obsolete attribute. Person max = Person.Create(("Max", "Mustermann")); Assert.AreEqual("Max",max.FirstName); var service = MyService.Create(("MyUser", "MyPassword")); Assert.AreEqual("MyUser", service.Config.UserName); }

编辑: 这是一个基于你的绘图示例的例子,它甚至强制了接口抽象

        public abstract class BaseWithAbstraction<TSelf, TInterface, TParameter>
        where TSelf : BaseWithAbstraction<TSelf, TInterface, TParameter>, TInterface, new()
    {
        [Obsolete(FactoryMessage, true)]
        protected BaseWithAbstraction()
        {
        }

        protected const string FactoryMessage = "Use YourClass.Create(...) instead";
        public static TInterface Create(TParameter parameter)
        {
            var me = new TSelf();
            me.Initialize(parameter);

            return me;
        }

        protected virtual void Initialize(TParameter parameter)
        {

        }
    }



    public abstract class BaseWithParameter<TSelf, TInterface, TParameter> : BaseWithAbstraction<TSelf, TInterface, TParameter>
        where TSelf : BaseWithParameter<TSelf, TInterface, TParameter>, TInterface, new()
    {
        protected TParameter Parameter { get; private set; }

        [Obsolete(FactoryMessage, true)]
        protected BaseWithParameter()
        {
        }
        protected sealed override void Initialize(TParameter parameter)
        {
            this.Parameter = parameter;
            this.OnAfterInitialize(parameter);
        }

        protected virtual void OnAfterInitialize(TParameter parameter)
        {
        }
    }


    public class GraphicsDeviceManager
    {

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

    internal abstract class Drawable<TSelf> : BaseWithParameter<TSelf, IDrawable, GraphicsDeviceManager>, IDrawable 
        where TSelf : Drawable<TSelf>, IDrawable, new()
    {
        [Obsolete(FactoryMessage, true)]
        protected Drawable()
        {
        }

        public abstract void Update();
        public abstract void Draw();
    }

    internal class Rectangle : Drawable<Rectangle>
    {
        [Obsolete(FactoryMessage, true)]
        public Rectangle()
        {
        }

        public override void Update()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }

        public override void Draw()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }
    }
    internal class Circle : Drawable<Circle>
    {
        [Obsolete(FactoryMessage, true)]
        public Circle()
        {
        }

        public override void Update()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }

        public override void Draw()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }
    }


    [Test]
    public void FactoryTest()
    {
        // doesn't compile because interface abstraction is enforced.
        Rectangle rectangle = Rectangle.Create(new GraphicsDeviceManager());

        // you get only the IDrawable returned.
        IDrawable service = Circle.Create(new GraphicsDeviceManager());
    }

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

假设接口是一个必须以指定方式使用的契约。以下方法在某些情况下可能是可行的替代方案:

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;
    }

}

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

缺点是,因为它是一种类类型,所以它不能用于接口可以使用的任何多继承类型场景。

我发现解决这个问题的一个方法是将施工分离到一个单独的工厂。例如,我有一个名为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);
}

现在我终于可以在没有new()约束的情况下编写泛型队列类了,在我的例子中,new()约束是主要问题。

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;
    }
}

现在我可以创建一个满足条件的实例

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

希望有一天这能帮助其他人解决问题,显然,为了显示问题和解决方案,删除了大量内部代码

如前所述,在接口上不能有构造函数。但是,由于这是7年后谷歌中排名如此高的结果,我想我应该在这里补充一下——具体来说,是为了展示如何将抽象基类与现有的接口一起使用,并且可能会减少将来在类似情况下所需的重构量。在一些评论中已经暗示了这个概念,但我认为值得展示如何实际做到这一点。

到目前为止你的主界面是这样的:

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

现在用要强制的构造函数创建一个抽象类。实际上,自从你写你最初的问题以来,它就已经可用了,我们可以在这里稍微花点时间,在这种情况下使用泛型,这样我们就可以适应其他可能需要相同功能但有不同构造函数要求的接口:

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

    }
}

现在你需要创建一个继承IDrawable接口和MustInitialize抽象类的新类:

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
    }
}

然后只需创建一个Drawable实例,就可以了:

IDrawable drawableService = new Drawable(myGraphicsDeviceManager);

这里很酷的是,我们创建的新Drawable类仍然像我们期望的IDrawable一样。

如果需要向MustInitialize构造函数传递多个参数,可以创建一个类,为需要传递的所有字段定义属性。