继承构造函数 - interface c#




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

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

你如何在C#界面中定义构造函数?

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

IDrawable
+更新
+绘制

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

现在我写下了这个,我想我在这里实现的是IObservable ,而GraphicsDeviceManager应该采用IDrawable ...看起来要么我没有得到XNA框架,要么框架没有被很好地思考。

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


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

interface IPerson
{
    IPerson(string name);
}

interface ICustomer
{
    ICustomer(DateTime registrationDate);
}

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

按照惯例,“接口构造函数”的实现由类型名称替换。

现在创建一个实例:

ICustomer a = new Person("Ernie");

我们是否会说遵守ICustomer合约?

那这个怎么样:

interface ICustomer
{
    ICustomer(string address);
}

你不能。

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

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


你可以用泛型技巧来做到这一点,但它仍然容易受到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
}

你没有。

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


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

鉴于接口是必须以指定方式使用的合约。 对于某些情况,以下方法可能是一种可行的替代方法:

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

}

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

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


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

如果你在那里创建一个具有构造函数的基类,它接受你需要的参数,那么每个从它衍生出来的类都需要提供它们。

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

接口的目的是强制执行某个对象签名。 它应该明确地不关心对象如何在内部工作。 因此,从概念的角度来看,界面中的构造函数并没有什么意义。

但有一些替代方案:

  • 创建一个充当最小默认实现的抽象类。 该类应该有你期望实现类的构造函数。

  • 如果您不介意矫枉过正,请使用AbstractFactory模式并在工厂类接口中声明具有所需特征的方法。

  • GraphicsDeviceManager作为参数传递给UpdateDraw方法。

  • 使用组合对象编程框架将GraphicsDeviceManager传递到需要它的对象部分。 在我看来,这是一个相当实验性的解决方案。

你所描述的情况一般不易处理。 类似的情况是业务应用程序中需要访问数据库的实体。


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

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


解决这个问题的一个办法就是把建筑分成一个单独的工厂。 例如,我有一个名为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()约束,这在我的情况下是主要问题。

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())

希望这可以帮助别人解决问题,显然很多内部代码都是为了解决问题和解决方案


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

请注意,这只是经过语法验证的伪代码,可能存在运行时警告,我在此处缺少:

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对象。





constructor