有办法吗?

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

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

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

该接口将位于组件内部

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

有帮助吗?

解决方案

胡安·曼努埃尔说:

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

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

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

public class Something : ITest<String>
{
  private Something() { }
}

有些东西源自 ITest<T>,但没有实现无参数构造函数。它会编译得很好,因为 String 确实实现了无参数构造函数。同样,约束是在 T 上,因此是在 String 上,而不是在 ITest 或 Something 上。由于满足 T 的约束,因此可以编译。但在运行时会失败。

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

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

注意新的约束:时间:ITest<T>.此约束指定您传递给 ITest<T> 的实参参数的内容 必须派生 来自 ITest<T>。

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

public class A : ITest<A>
{
}

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

其他提示

不要太直白,但您误解了接口的目的。

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

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

胡安,

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

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

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

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

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

您可以使用 类型参数约束

interface ITest<T> where T: new()
{
    //...
}

class Test: ITest<Test>
{
    //...
}

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

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才是真正重要的。工厂只是一个方便的类 提供默认构造函数。这是最简单且通常也是最好的解决方案。

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

public IInterface CreateUsingDelegate(Func<IInterface> createCallback)
{
    return createCallback();
}

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

这里的优点是代码短小简单,可以与 任何 构造方法,并且(带有闭包)让您可以轻松传递构造对象所需的附加数据。

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

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

我不这么认为。

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

我想提醒大家的是:

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

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

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

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

interface FooFactory {
    Foo createInstance();
}

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

激活器不需要无参数构造函数来实例化您的类。您可以拥有一个参数化构造函数并传递来自激活器的所有参数。查看 MSDN 对此.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top