C#使用泛型和接口实现

Sug*_*gar 8 .net c# generics

上下文:.NET 4.0,C#

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

一个简化的例子就是这个:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

编辑:我设计接口的方式使它们应该独立于实现它们的具体条款.可以从dll加载具体的clases,但是大多数应用程序都可以使用接口.在某些情况下,我需要使用具体的clases,特别是在使用需要序列化的clases时.

提前致谢.

亚历杭德罗

D S*_*ley 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;
}
Run Code Online (Sandbox Code Playgroud)


Tam*_*eer 10

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

interface IForm<out T> where T : IField
{

}
Run Code Online (Sandbox Code Playgroud)

有关协方差和逆变的更多信息,请点击此处.


BTo*_*TKD 7

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

你已经说过你正在使用IField接口中声明的方法,所以可能没有必要让你的IForm类通用 - 只需要存储对IField的引用,而不是通用参数'T'(已经保证)无论如何要成为IField).

例如,使用:

public interface IForm
{
    IEnumerable<IField> Fields { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

代替

public interface IForm<T> where T : IField
{
    IEnumerable<T> Fields { get; set; }
}
Run Code Online (Sandbox Code Playgroud)