我有一个接口 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#泛型中是否还有其他规则类型转换?
答案 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)方法的不同签名,因此它们不相关,而是像两个单独的类一样。