C# 方法返回类型多态性
我有4个C#类<代码>作业,C# 方法返回类型多态性,c#,generics,polymorphism,C#,Generics,Polymorphism,我有4个C#类作业,构建作业,作业工厂和构建作业工厂。以下是每个班级的MVP public class Job { } public abstract class JobFactory { public abstract List<Job> GetJobs(List<B> bs); } public class BuildJob : Job { A a; B b; public BuildJob(A a, B b) {
构建作业
,作业工厂
和构建作业工厂
。以下是每个班级的MVP
public class Job {
}
public abstract class JobFactory {
public abstract List<Job> GetJobs(List<B> bs);
}
public class BuildJob : Job {
A a;
B b;
public BuildJob(A a, B b) {
this.a = a;
this.b = b;
}
}
public class BuildJobFactory : JobFactory {
A a;
public override List<Job> GetJobs(List<B> bs) {
return bs.ConvertAll(b => new BuildJob(a, b));
}
}
我试图创建一个类型为JobFactory
的变量,但没有泛型声明(JobFactory currentJobFactory;
),因为它在编译时是未知的,因为在运行时,该变量将被分配给某个类的某个实例,该类扩展了JobFactory
,具有未知的泛型,但这并不像在Java中那样有效
如何解决这些问题之一?试试:
public override List<Job> GetJobs(List<B> bs) {
return bs.Select(b => new BuildJob(a, b)).Cast<Job>().ToList();
}
这将指示编译器在System.Linq
命名空间中搜索扩展方法(其中Select()
是其中之一)
这是在做什么:
bs.Select()
迭代bs
列表,对每个列表执行lambda,生成一个IEnumerable
.Cast()
将其转换为IEnumerable
,最后,.ToList()
将IEnumerable
转换为列表
上述所有的方法,我会考虑更改方法的签名以返回<代码> iQueLabe<代码>,这将消除对<代码>的需要。Case.[,Telist](< /Cult> .< /P> < p>泛型在C中比java中的泛型要严格得多。您不能忽略泛型和默认解释,即一切都是一个
对象
。但是,您可以使用来解决这种情况
如果更改泛型,使其如下所示:
public abstract class JobFactory<out T>
where T : Job, new()
{
public abstract List<T> GetJobs(List<B> bs);
}
public class Container
{
public JobFactory<Job> Factory { get; set; }
}
Container myContainer = new Container {
Factory = new JobFactory<BuildJob>()
};
公共抽象类JobFactory
其中T:Job,new()
{
公共摘要列表GetJobs(列表bs);
}
然后,您可以自由地将作业工厂
转换为作业工厂
,而不会出现问题。这就是IEnumerable
的定义方式。您可以围绕基本假设构建核心代码的逻辑,但可以进一步专门化
基本上,这意味着你可以做到:
JobFactory<BuildJob> derivedFactory = new JobFactory<BuildJob>();
JobFactory<Job> baseFactory = derivedFactory;
JobFactory-derivedFactory=新的JobFactory();
JobFactory baseFactory=派生工厂;
或者更直接地,您可以使用如下代码:
public abstract class JobFactory<out T>
where T : Job, new()
{
public abstract List<T> GetJobs(List<B> bs);
}
public class Container
{
public JobFactory<Job> Factory { get; set; }
}
Container myContainer = new Container {
Factory = new JobFactory<BuildJob>()
};
公共类容器
{
public JobFactory工厂{get;set;}
}
然后按如下方式分配该属性:
public abstract class JobFactory<out T>
where T : Job, new()
{
public abstract List<T> GetJobs(List<B> bs);
}
public class Container
{
public JobFactory<Job> Factory { get; set; }
}
Container myContainer = new Container {
Factory = new JobFactory<BuildJob>()
};
Container myContainer=新容器{
工厂=新作业工厂()
};
不能将构建作业列表作为作业列表返回,但可以将构建作业添加到作业列表中
例如:
public override List<Job> GetJobs(List<B> bs) {
List<Job> temp = new List<Job>();
foreach (var b in bs) {
temp.Add(new BuildJob(new A(), b));
}
return temp;
}
public覆盖列表GetJobs(列表bs){
列表温度=新列表();
foreach(bs中的var b){
临时添加(新构建作业(新的A(),b));
}
返回温度;
}
不像LINQ语句那样流畅和内联,而是功能性的
我同意其他人的看法,IEnumerable也是一种更好的返回类型。使用IEnumerable
或IReadOnlyCollection
而不是List
,因为这两个接口都支持协方差。无论如何,返回具体的集合类型被认为是不好的做法,因为它暴露了很多实现细节
如果您想要延迟超额,请选择IEnumerable
;如果您不想延迟超额,请选择IReadOnlyCollection
public class Job
{ }
public abstract class JobFactory
{
public abstract IEnumerable<Job> GetJobs(IEnumerable<B> bs);
}
public class BuildJob : Job
{
A a;
B b;
public BuildJob(A a, B b)
{
this.a = a;
this.b = b;
}
}
public class BuildJobFactory : JobFactory
{
A a;
public override IEnumerable<Job> GetJobs(IEnumerable<B> bs)
{
return bs.Select(b => new BuildJob(a, b));
}
}
公共类作业
{ }
公共抽象类JobFactory
{
公共抽象IEnumerable GetJobs(IEnumerable bs);
}
公共类BuildJob:Job
{
A A;
B B;
公共建筑工程(A、B)
{
这个a=a;
这个.b=b;
}
}
公共类BuildJobFactory:JobFactory
{
A A;
公共覆盖IEnumerable GetJobs(IEnumerable bs)
{
返回bs.Select(b=>newbuildjob(a,b));
}
}
请参阅:有关协方差和逆变换的更多信息。我可以问一下您如何使用JobFactory
?因为我个人不认为第二个例子有什么问题,但是你会遇到的唯一问题是如果你想要一个地方来构建一个作业
,比如一个作业生成器
,但是我不知道这是否是你的用例?使用IEnumerable我已经尝试过了,但是得到了错误“类型参数T必须在JobFactory.GetJobs(列表)上始终有效。“协变是协变的”,我不太理解它。你不能将协变分配给抽象类,你必须创建一个接口。即使它是一个接口,协变也不能用于List
,因为List
是一个具体的类(也不能用于IList
,因为它不协变)我确实使它成为一个带有以下标题的接口公共接口JobFactory,其中T:Job,new(){
感谢您的反馈,但不幸的是,我正在使用Unity,它的列表
版本没有选择
方法。我也添加了我的答案,但尝试使用System.Linq;
将添加到文件顶部。