C#泛型之间是否有类型转换规则?

时间:2016-03-16 14:18:22

标签: c# generics

我有一个接口 IJob ,所有Job类都从该接口继承而且我有一个通用的repo类,它将处理所有类型的IJob。

我遇到的问题是即使Repository<Job1>Repository<IJob>的类型,我也无法将Job1转换为IJob

代码

internal class Program
{
    public interface IJob { }
    public class Job1 : IJob { }
    public class Job2 : IJob { }

    public class Repository<TJob>
        where TJob : IJob
    {
        public List<TJob> GetJobs()
        {
            return new List<TJob>();
        }
    }

    private static void Main(string[] args)
    {
        IJob iJob = new Job1(); // Valid
        Repository<IJob> repo = new Repository<Job1>(); // Not Valid
    }
}

有人能告诉我为什么在C#中不可能这样做,C#泛型中是否还有其他规则类型转换?

4 个答案:

答案 0 :(得分:18)

如果你想要协方差,那么你必须为存储库引入一个通用接口,并将GetJobs方法的返回类型更改为IEnumerable<TJob>

internal class Program
{
    public interface IJob { }
    public class Job1 : IJob { }
    public class Job2 : IJob { }

    public interface IRepository<out TJob> where TJob : IJob
    {
        IEnumerable<TJob> GetJobs();
    }

    public class Repository<TJob> : IRepository<TJob> where TJob : IJob
    {
        public IEnumerable<TJob> GetJobs()
        {
            return new List<TJob>();
        }
    }

    private static void Main(string[] args)
    {
        IJob iJob = new Job1(); // Valid
        IRepository<IJob> repo = new Repository<Job1>(); // Also valid
    }
}

有关协方差和逆变的更多信息,请参阅:https://msdn.microsoft.com/en-us/library/dd799517%28v=vs.110%29.aspx

答案 1 :(得分:11)

Repository<IJob> repo = new Repository<Job1>(); // Not Valid

是的,因为它不是Repository<IJob>。使用Repository<IJob>时,此行有效:

repo.GetJobs().Add(new Job2());

现在,使用Repository<Job1>,此行无效。它不会编译。

所以你得到的错误是正确的。 Repository<Job1> a Repository<IJob>

答案 2 :(得分:2)

你只想要

Repository<IJob> repo = new Repository<IJob>();

然后您可以将任何IJob添加到存储库。

repo.Add(new Job1());
repo.Add(new Job2());

答案 3 :(得分:1)

要理解为什么无法完成,我们需要回到c#中的对象的子类。当你遇到这样的情况时:

public class A 
{
    public A GetInstance { get;set;}
}

public class B : A
{

}

B类继承A类中的所有方法,包括方法的签名。实际上,你可以创建一个B实例,它有一个GetInstance方法,但是不是B.如果你试图覆盖GetInstance方法来返回B,它当然会产生一个编译错误(如果一个方法不能被抛弃,那么只有改变才是返回类型。)

使用泛型有点不同,因为更改输入中的类型将改变所有方法的签名。

简单地说,即使Job1是IJob的子类,类Repository(IJob)的方法也有类Repository(Job1)方法的不同签名,因此它们不相关,而是像两个单独的类一样。