对于实现接口的类型,你怎么能要求一个没有参数的构造函数呢?

Posted

技术标签:

【中文标题】对于实现接口的类型,你怎么能要求一个没有参数的构造函数呢?【英文标题】:How can you require a constructor with no parameters for types implementing an interface? 【发布时间】:2010-09-06 19:33:33 【问题描述】:

有办法吗?

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

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

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

接口将在程序集内部

如果您对这种没有接口的场景有建议,我很乐意考虑...

【问题讨论】:

【参考方案1】:

不要太直白,但你误解了接口的用途。

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

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

【讨论】:

【参考方案2】:

您可以使用type parameter constraint

interface ITest<T> where T: new()

    //...


class Test: ITest<Test>

    //...

【讨论】:

【参考方案3】:

Juan Manuel said:

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

这是一种间接机制。泛型允许您“作弊”并将类型信息与接口一起发送。这里要记住的关键是约束不在您直接使用的接口上。它不是对界面本身的约束,而是对将在界面上“顺势而为”的其他类型的约束。恐怕这是我能提供的最好解释了。

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

public class Something : ITest<String>

  private Something()  

Something 派生自 ITest,但没有实现无参数构造函数。它会编译得很好,因为 String 确实实现了一个无参数的构造函数。同样,约束在 T 上,因此在 String 上,而不是在 ITest 或某事上。由于满足了对 T 的约束,这将编译。但它会在运行时失败。

为防止某些个实例出现此问题,您需要在 T 中添加另一个约束,如下所示:

public interface ITest<T>
  where T : ITest<T>, new()


注意新的约束:T : ITest。此约束指定您传递给 ITest 的自变量参数的内容必须派生自 ITest

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

public class A : ITest<A>



public class B : ITest<A>

  private B()  

【讨论】:

【参考方案4】:

胡安,

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

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

不幸的是,无法将接口、抽象类或虚拟方法与构造函数或静态方法结合使用。简短的原因是前者不包含显式类型信息,而后者需要显式类型信息。

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

接口、抽象类或虚拟方法的全部意义在于能够在没有显式类型信息的情况下进行函数调用,这是通过存在一个实例来实现的引用,它具有调用代码不能直接使用的“隐藏”类型信息。因此,这两种机制非常简单地相互排斥。它们不能一起使用,因为当你混合它们时,你最终在任何地方都没有具体的类型信息,这意味着运行时不知道在哪里可以找到你要求它调用的函数。

【讨论】:

【参考方案5】:

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

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 实际上一个默认构造函数。此外,如果这恰好是性能关键代码,反射会有点慢。

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

public interface IFactory

    IInterface Create();


public class Factory<T> 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<Foo>());

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

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

public IInterface CreateUsingDelegate(Func<IInterface> createCallback)

    return createCallback();


public void Test()

    IInterface thing = CreateUsingDelegate(() => new Foo());

这里的优点是代码短而简单,可以使用任何构造方法,并且(使用闭包)可以让您轻松传递构造对象所需的额外数据。 p>

【讨论】:

【参考方案6】:

使用该类型调用 RegisterType 方法,并使用泛型对其进行约束。然后,无需遍历程序集来查找 ITest 实现者,只需存储它们并从那里创建。

void RegisterType<T>() where T:ITest, new() 

【讨论】:

【参考方案7】:

我不这么认为。

您也不能为此使用抽象类。

【讨论】:

【参考方案8】:

我想提醒大家:

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

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

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

【讨论】:

【参考方案9】:

不,你不能那样做。也许对于您的情况,工厂界面会有所帮助?比如:

interface FooFactory 
    Foo createInstance();

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

【讨论】:

【参考方案10】:

激活器不需要无参数构造函数来实例化您的类。您可以有一个参数化的构造函数并从 Activator 传递所有参数。查看MSDN on this。

【讨论】:

以上是关于对于实现接口的类型,你怎么能要求一个没有参数的构造函数呢?的主要内容,如果未能解决你的问题,请参考以下文章

Java重载覆写thissuper抽象类接口

jmeter实现调用要求签名的接口

golang reflect反射(一):interface接口的入门(大白话)

java中,实现接口的方法的过程是重写吗?

java类的构造函数的参数为接口类型,如何传值?

13 接口