I have 4 C# classes; Job, BuildJob, JobFactory and BuildJobfactory. Below are the MVPs of each class.
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 is used to create a load of jobs from a list of B instances, and the way that those jobs are constructed will depend on their types (BuildJob, DestroyJob et.c) so this has to be left to a factory class. As I come from a Java background, I assumed that returning a List<BuildJob> from a method whose return type is declared as List<Job> would be fine, as BuildJob extends Job, but this does not work in C#.
To alleviate this, I then tried generics so the modified classes looked like so.
public abstract class JobFactory<T> where T : Job, new() {
public abstract List<T> GetJobs(List<B> bs);
}
public class BuildJobFactory : JobFactory<BuildJob> {
A a;
public override List<BuildJob> GetJobs(List<B> bs) {
return bs.ConvertAll(b => new BuildJob(a, b));
}
}
I tried to make a variable of type JobFactory without a generic declaration (Jobfactory currentJobFactory;) as it will be unknown at compile time, since at runtime the variable will be assigned to some instance of some class that extends JobFactory with some unknown generic, but this does not work as it does in Java.
How could I solve one of these problems?
Try:
public override List<Job> GetJobs(List<B> bs) {
return bs.Select(b => new BuildJob(a, b)).Cast<Job>().ToList();
}
Edit: If Select() is unavailable, you probably need to add the following to the beginning of your file:
using System.Linq;
This will instruct the compiler to search for extension methods (which Select() is one of) in the System.Linq namespace.
What this is doing:
bs.Select() iterates over the bs list, executing the lambda on each one, resulting in an IEnumerable<BuildJob>. .Cast<Job>() converts that to an IEnumerable<Job>, and finally, .ToList() converts the IEnumerable<Job> to a List<Job>.
All that said, I would consider changing the signatures of your methods to return IEnumerable<Job>, which would remove the need for the .Cast<Job>().ToList().
You cannot return a List of BuildJobs as a List of Jobs, but you can add a BuildJob to a List of Jobs.
For Example:
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;
}
Not as slick and inline as a LINQ statement, but functional.
I agree with the rest that IEnumerable is a better return type, as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With