Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 方法返回类型多态性_C#_Generics_Polymorphism - Fatal编程技术网

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) {

我有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) {
        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;
添加到文件顶部。