如何为实现接口的类型要求没有参数的构造函数?

有办法吗?

我需要实现特定接口的所有类型都有一个无参数构造函数,可以这样做吗?

我正在为我公司的其他开发人员开发基本代码,以便在特定项目中使用。

有一个进程将创建执行某些任务的类型(在不同的线程中)的实例,我需要这些类型遵循特定的合同(ergo,接口)。

界面将在程序集内部

如果您对没有接口的情况有建议,我很乐意将其考虑在内……

胡安曼努埃尔说:

这是我不明白为什么它不能成为界面合同的一部分的原因之一

这是一种间接机制。 通用允许您“欺骗”并与界面一起发送类型信息。 这里要记住的关键是,约束不在您直接使用的接口上。 它不是对接口本身的约束,而是在接口上“骑行”的其他类型。 这是我能提供的最佳解释,我担心。

通过这个事实的说明,我将指出我在aku的代码中注意到的一个漏洞。 当你尝试实例化时,可以编写一个可以正常编译但在运行时失败的类:

public class Something : ITest { private Something() { } } 

某些东西来自ITest ,但不实现无参数构造函数。 它将编译正常,因为String确实实现了无参数构造函数。 同样,约束是在T上,因此是字符串,而不是ITest或Something。 由于满足T的约束,这将编译。 但它会在运行时失败。

要防止此问题的某些实例,您需要向T添加另一个约束,如下所示:

 public interface ITest where T : ITest, new() { } 

请注意新约束:T:ITest 。 此约束指定传递给ITest 的参数参数的内容也必须从ITest 派生

即便如此,这也不会阻止所有洞的情况。 下面的代码编译正常,因为A有一个无参数构造函数。 但由于B的无参数构造函数是私有的,因此使用您的进程实例化B将在运行时失败。

 public class A : ITest { } public class B : ITest { private B() { } } 

不要太生硬,但你误解了接口的用途。

接口意味着有几个人可以在自己的类中实现它,然后将这些类的实例传递给其他要使用的类。 创造创造了不必要的强耦合。

听起来你真的需要某种注册系统,要么让人们注册实现接口的可用类的实例,要么是可以根据请求创建所述项目的工厂。

胡安,

不幸的是,没有办法用强类型语言解决这个问题。 您将无法在编译时确保这些类能够由基于Activator的代码实例化。

(编辑:删除了错误的替代解决方案)

原因在于,遗憾的是,不能将接口,抽象类或虚方法与构造函数或静态方法结合使用。 原因很简单,前者不包含显式类型信息,后者需要显式类型信息。

构造函数和静态方法必须在调用时具有显式(在代码中的正确)类型信息。 这是必需的,因为没有涉及类的实例,运行时可以查询该实例以获取基础类型,运行时需要确定调用哪个实际的具体方法。

接口,抽象类或虚方法的整个要点是能够在没有显式类型信息的情况下进行函数调用,并且这是通过引用实例的事实实现的,该实例具有“隐藏”类型信息而不是直接可用于调用代码。 所以这两种机制完全相互排斥。 它们不能一起使用,因为当你混合它们时,你最终根本就没有具体的类型信息,这意味着运行时不知道在哪里找到你要求它调用的函数。

您可以使用类型参数约束

 interface ITest where T: new() { //... } class Test: ITest { //... } 

所以你需要一个可以创建实现接口的未知类型实例的东西 。 您基本上有三个选项:工厂对象,Type对象或委托。 这是给予的:

 public interface IInterface { void DoSomething(); } public class Foo : IInterface { public void DoSomething() { /* whatever */ } } 

使用Type非常难看,但在某些情况下有意义:

 public IInterface CreateUsingType(Type thingThatCreates) { ConstructorInfo constructor = thingThatCreates.GetConstructor(Type.EmptyTypes); return (IInterface)constructor.Invoke(new object[0]); } public void Test() { IInterface thing = CreateUsingType(typeof(Foo)); } 

最大的问题是,在编译时,你不能保证Foo实际上一个默认的构造函数。 此外,如果这恰好是性能关键代码,则reflection有点慢。

最常见的解决方案是使用工厂:

 public interface IFactory { IInterface Create(); } public class Factory where T : IInterface, new() { public IInterface Create() { return new T(); } } public IInterface CreateUsingFactory(IFactory factory) { return factory.Create(); } public void Test() { IInterface thing = CreateUsingFactory(new Factory()); } 

在上面,IFactory才是真正重要的。 对于提供默认构造函数的类,Factory只是一个便利类。 这是最简单且通常最好的解决方案。

第三个当前不常见但很可能变得更常见的解决方案是使用委托:

 public IInterface CreateUsingDelegate(Func createCallback) { return createCallback(); } public void Test() { IInterface thing = CreateUsingDelegate(() => new Foo()); } 

这里的优点是代码简短,可以使用任何构造方法,并且(使用闭包)可以轻松传递构造对象所需的其他数据。

使用类型调用RegisterType方法,并使用generics约束它。 然后,而不是走动程序集来找到ITest实现者,只需存储它们并从那里创建。

 void RegisterType() where T:ITest, new() { } 

我不这么认为。

您也不能使用抽象类。

我想提醒大家:

  1. 在.NET中编写属性很容易
  2. 在.NET中编写静态分析工具可以很容易地确保符合公司标准

编写一个工具来获取实现某个接口/具有属性并validation它具有无参数构造函数的所有具体类需要大约5分钟的编码工作量。 您可以将其添加到构建后步骤中,现在您可以使用框架来执行您需要执行的任何其他静态分析。

语言,编译器,IDE,你的大脑 – 它们都是工具。 使用它们!

不,你不能那样做。 也许对于您的情况,工厂界面会有帮助吗? 就像是:

 interface FooFactory { Foo createInstance(); } 

对于Foo的每个实现,您都要创建一个知道如何创建它的FooFactory实例。

您不需要Activator的无参数构造函数来实例化您的类。 您可以使用参数化构造函数并传递Activator中的所有参数。 在这上面查看MSDN 。