DLang - 模板约束 - 类型必须实现接口

DLang - Template constraints - type must implement interface

我正在尝试将以下 C# 代码转换为 D,但是我不知道如何使模板约束起作用。

C# 实现

public interface IComponent
{

} 

public class Container
{
    public T CreateComponent<T>() where T: IComponent, new()
    {
        // Trivial initialisation for example
        var t = new T(); 
        return t;
    }
}

D 实现

public interface Component
{

}

public class Container
{
    public T createComponent(T)()
    {
        // Trivial initialisation for example
        auto t = new T();
        return t;
    }
}

如何重新创建 "where T: IComponent" 约束?

我尝试了各种组合 is、typeof 等的表达式,但找不到任何有效的方法。

以典型的方式,我在此处询问后立即找到了答案 http://ddili.org/ders/d.en/is_expr.html

public T addComponent(T)()
    if (is(T: Component))

好吧,如果您要做的只是要求 T 实现接口 IComponent,那么 is(T : IComponent) 将测试 T 是否可以隐式转换为IComponent(当 IComponentT 的基础 class 或其实现的接口时就是这种情况)。所以,你最终会得到类似

的东西
public class Container
{
    public T createComponent(T)()
        if(is(T : IComponent))
    {
        // Trivial initialisation for example
        auto t = new T();
        return t;
    }
}

现在,从技术上讲,如果使用 alias this 来定义隐式转换,则其他内容也可以匹配,这不太可能是常见的,但如果你对它更偏执,你可以该约束还检查 T 是否为 class - is(T == class).

public class Container
{
    public T createComponent(T)()
        if(is(T == class) && is(T : IComponent))
    {
        // Trivial initialisation for example
        auto t = new T();
        return t;
    }
}

那么,T 必须是一个 class,并且它必须隐式转换为 IComponent。但是, 在技术上仍然有可能 T 成为一个 class,它没有实现 IComponent 但确实定义了一个 alias this它转换为 IComponentT 不再可能成为执行此操作的结构)。所以,它并不完美,但我不知道有什么方法可以确保隐式转换是通过继承而不是 alias this 完成的。所以,不幸的是,我不知道有什么方法可以绝对保证 T 是实现 IComponent 的 class。我知道的最多的事情是确保它隐式转换为 `IComponent,几乎 总是意味着它实现它。

然而,实际情况是,在绝大多数情况下,只需检查 is(T : IComponent) 就足够了,并且根据您的代码编写方式,它甚至可能适用于隐式转换的类型IComponent 但实际上不是 IComponent。因此,alias this 在工作中抛出扳手的事实可能实际上不是问题。但是,一般来说,alias this 是泛型代码的祸根,也是为什么大多数泛型代码不应该检查隐式转换的原因。一个类型很容易通过 alias this 进行隐式转换,但实际上并没有在函数中进行转换,在这种情况下,它要么无法编译,要么如果它支持与目标类型确实如此,但这些操作的结果与原始类型实际转换为目标类型时的结果不同。因此,如果您实际上想要 模板代码中的隐式转换,您应该通过将参数分配给目标类型来强制进行隐式转换。但是由于您要测试的是接口而不是一般的隐式转换,您可能想要的是一个测试,该测试不允许通过 alias this 进行隐式转换。不幸的是,我知道在编译时检查一种类型是否派生自另一种类型或实现特定接口的唯一方法是检查它是否隐式转换为该基 class 或接口。

但也许有一些有趣的巫毒教具有实际上能够做到这一点的特征。如果有,我们可能应该为 std.traits 添加一些东西,它会为你做这件事,如果没有,也许我们应该找到一种方法来添加它,因为如果你 alias this 肯定会很烦人不想要它。但幸运的是,这不是大多数代码中出现的问题,如果您没有编写 public API,那么您只需要在使用 [= 声明类型时担心它19=]。如果你不是,那真的没关系。

您甚至不需要模板约束,只需要模板专业化:

T createComponent(T : IComponent)() { /* some code */ }