CSharp - 接口, 用于定义一个构造函数的签名?

  显示原文与译文双语对照的内容

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

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

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

IDrawable
+Update
+Draw

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

现在我写下来了,我想我在这里实现的是 IObservable,而 GraphicsDeviceManager 应该是 IDrawable 。 似乎我没有获得XNA框架,或者框架没有很好地被认为。

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

时间:

你不能。它有时候是痛苦的,但是你不能用普通的技术来调用它。

在一篇博客文章中我建议了静态接口,它只能在泛型类型约束中使用- 但是可以非常方便,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)
 {
 }
}

一个非常晚的贡献,演示了接口构造函数的另一个问题。 ( 我选择这个问题,因为它有问题的最清晰的清晰度) 。 假设我们可以:


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

你不能。

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

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

它是泛型类型定义一个接口,用于定义构造函数,但它 是能够定义一个接口,它将强制使用泛型的类型来有paramerterless构造函数,它甚至是一个非常丑陋的语法- - 实际上我并不确定这是不是一个好的编码模式。


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
}

另一方面,如果你想测试某个类型是否具有paramerterless构造函数,可以使用反射进行:


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

希望这有帮助

我在回头看看这个问题然后我心想,也许我们正在aproaching这个问题不是正确的方法。 当关注定义具有某些参数的构造函数时,接口可能不是方法。。 但是( 抽象画) 基类是。

如果你在那里创建了一个基类,它接受你需要的参数,那么derrives中的每个类都需要提供它们。


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

通用工厂方法似乎还是理想的。 你可以判定该工厂要求模型的输入参数,这些参数被传递到构造函数的一排你不会因此发生这种情况,它的对象实例化的。

注意,这只是验证了伪代码,可能有一个run-time警告我在这里丢失:


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() 可以为一个新的GraphicsDeviceManager对象来"询问"容器。

解决这个问题的一种方法是把建筑分离成单独的工厂。 例如我有一个名为IQueueItem的抽象类,我需要一种方法来将那个对象转换成另一个对象( CloudQueueMessage ) 。 所以在接口IQueueItem上我有-


public interface IQueueItem
{
 CloudQueueMessage ToMessage();
}

现在,我还需要一个实际的队列类的方法来将CloudQueueMessage转换回 IQueueItem - IE 需要静态构造( 比如 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())

希望这有一天能帮助别人,显然有很多内部代码被删除,试图显示问题和解决方案

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

}

...