8

上下文:.NET 4.0,C#

我正在创建一组接口和一组实现它们以提供一些服务的类。客户端使用具体的类,但调用使用接口作为参数类型声明的方法。

一个简化的例子是这个:

namespace TestGenerics
{
    // Interface, of fields
    interface IField
    {
    }

    // Interface: Forms (contains fields)
    interface IForm<T> where T : IField
    {

    }

    // CONCRETE CLASES
    class Field : IField
    {   
    }

    class Form <T> : IForm<T> where T : IField
    {
    }

    // TEST PROGRAM
    class Program
    {
        // THIS IS THE SIGNATURE OF THE METHOD I WANT TO CALL
        // parameters are causing the error.
        public static void TestMethod(IForm<IField> form)
        {
            int i = 1;
            i = i * 5;
        }

        static void Main(string[] args)
        {
            Form<Field> b = new Form<Field>();
            Program.TestMethod(b);
        }
    }
}

该代码对我来说很有意义,但我得到编译器错误:

参数 1:无法从 ' TestGenerics.Form<TestGenerics.Field>' 转换为 ' TestGenerics.IForm<TestGenerics.IField>' TestGenerics

我不确定我做错了什么,我在互联网上阅读了很多页面,但没有一个能解决我的问题。

是否有一个解决方案不会修改我正在尝试构建的架构:

编辑:我设计了接口,使它们应该独立于实现它们的具体类。具体的类可以从 dll 加载,但大多数应用程序都与接口一起工作。在某些情况下,我需要使用具体的类,特别是在使用需要序列化的类时。

提前致谢。

亚历杭德罗

4

3 回答 3

13

问题是Form<Field>实现IForm<Field>但不是IForm<IField>。您不能将继承的类(或接口)用作泛型参数,除非它被标记为与out标识符协变。但是,将您的界面标记为协变会显着限制使用(基本上是在“仅输出”界面中制作IEnumerable),因此它可能不适合您。

使其工作的一种方法是也使其TestMethod通用:

public static void TestMethod<T>(IForm<T> form) where T:IField
{
    int i = 1;
    i = i * 5;
}
于 2013-07-30T15:24:47.550 回答
10

您可以使用协方差,如下所示:

interface IForm<out T> where T : IField
{

}

更多关于协变和逆变在这里

于 2013-07-30T15:29:29.807 回答
7

其他人已经指出了错误消息背后的原因,但让我们暂时检查一下示例代码的设计。也许您正在使用不需要的泛型。

您已经说过您正在使用在 IField 接口中声明的方法,因此可能不需要使您的 IForm 类通用 - 只需让它存储对 IField 的引用,而不是通用参数“T”(这已经得到保证无论如何要成为一个IField)。

例如,使用:

public interface IForm
{
    IEnumerable<IField> Fields { get; set; }
}

代替

public interface IForm<T> where T : IField
{
    IEnumerable<T> Fields { get; set; }
}
于 2013-07-30T16:20:25.917 回答