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

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

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

IDrawable +更新 +画

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

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

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


当前回答

通用工厂方法似乎仍然是理想的。您将知道工厂需要一个形参,而这些形参恰好被传递给正在实例化的对象的构造函数。

注意,这只是经过语法验证的伪代码,这里可能忽略了一个运行时警告:

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

当然,您只需要通过工厂创建实例来保证始终有一个适当初始化的对象。也许使用像AutoFac这样的依赖注入框架会有意义;Update()可以向IoC容器“请求”一个新的GraphicsDeviceManager对象。

其他回答

你不能。它偶尔会让人感到痛苦,但无论如何,使用正常的技术都无法调用它。

在一篇博客文章中,我建议静态接口只能在泛型类型约束中使用——但在我看来,它真的很方便。

如果你可以在一个接口中定义一个构造函数,那么你在派生类时就会遇到麻烦:

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

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

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

}

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

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
}

另一方面,如果你想测试一个类型是否有无参数构造函数,你可以使用反射来做:

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

希望这能有所帮助。