1

I'm trying to define an interface IScheduler that takes an T1 and returns a T2, and also has a type argument for an IJob<T1,T2> so that it knows what job to create. I'd like to call it as so:

public class SomeJob : IJob<string, int> // preferred way to use the method int result = scheduler.Schedule<SomeJob>("some_param"); 

and have the compiler infer that T1 is a string and T2 is an int. This is how I've tried defining the interface

public interface IScheduler { T2 Schedule<TJob, T1, T2>(T1 args) where TJob: IJob<T1, T2>; } 

Unfortunately, the compiler complains:

Using the generic method 'Schedule<TJob,T1,T2>(T1)' requires 3 type arguments The type 'SomeJob' must be convertible to 'Job<T1, T2>' in order to use it as parameter 'TJob` in the generic method 'T2 IScheduler.Schedule<TJob,T1,T2>(T1)' 

What I'd really like to do is this:

public interface IScheduler { T2 Schedule<TJob>(T1 args) where TJob: IJob<T1, T2>; } 
2
  • 1
    You can't, you must supply all generic arguments when calling Schedule. Commented Jan 4, 2017 at 21:09
  • 2
    there are two problems. first is that you cant define generic arguments partially. so when you write <SomeJob> you must define all. compiler doesn't support partially defining generic arguments in any case. second problem is that compiler can not infer the type int because int result is just the local variable. what would happen if you just call scheduler.Schedule and not storing the result anywhere? Commented Jan 4, 2017 at 21:18

1 Answer 1

1

It isn't quite possible to get the syntax that you're looking for, but here are some things that would work:

int result = scheduler.Schedule(new SomeJob(), "some_param"); // using this public interface IScheduler { T2 Schedule<T1, T2>(IJob<T1, T2> job, T1 args); } 

Or:

int result = scheduler.ForJob<SomeJob>.Schedule("some_param"); // using this public interface IScheduler { IJobScheduler<TJob> ForJob<TJob>(); } public interface IJobScheduler<out TJob> { } public static class Extensions { public static T2 Schedule<T1, T2>(this IJobScheduler<IJob<T1, T2>> job, T1 args) { ... } } 

Or if you can get rid of the return argument, you can access the strongly typed type of TJob in the Schedule method:

scheduler.ForJob<JobWithNoReturn>().Schedule("some_param"); // using the stuff from #2 and also this public static class Extensions { ... public static void Schedule<TJob, T1>(this IJobScheduler<TJob> job, T1 args) where TJob : IJob<T1> { ... } } 
Sign up to request clarification or add additional context in comments.

3 Comments

Don't both of these cause SomeJob to have to support any T1 or T2? Versus constraining them to string and int?
@Guvante: T1 and T2 in both of these cases will be based on the definition of SomeJob. Supposing it only implements IJob<string, int>, then T1 and T2 will be treated as string and int.
Hmm, interesting extension method magic. So you don't have to constrain ForJob<TJob>(); to only take IJob<>s because you only define an extension method when they do pass in an IJob<>. I think in my case I will call both IScheduler.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.