See comments... I want the 2nd MapPost call to fail at compile time. I'm just experimenting with asp.net minimal pipeline. I think this requires constrained generics but I'm new to C# so thought someone could quickly answer this one (hopefully!).
var router = new ExampleRouter();
var controller = new ExampleWebController();
router.MapPost("/api/ProcessJob", controller.ProcessJob);
// I would like this to be a compile time error, instead of a runtime startup error.
router.MapPost("/api/ProcessJob2", controller.InvalidHandler);
class ExampleWebController {
public ExampleWebController() { }
public void InvalidHandler() { }
public bool ProcessJob(Job job) { return true; }
}
class ExampleRouter {
public ExampleRouter() { }
// TODO: Check at compile that `handler` takes a DTO and returns bool
public void MapPost<TFunc>(string path, TFunc handler) {
var func_type = typeof(TFunc);
// Prints "System.Func" for ProcessJob
// Prints "System.Action" for InvalidHandler
Console.WriteLine(func_type);
var args = func_type.GetGenericArguments();
foreach (Type arg in args) {
// Prints "Job", "System.Boolean" for ProcessJob...awesome
Console.WriteLine(arg);
}
// Construct the DTO dynamically.
// In reality, we'd do this when a http request comes in.
var job_type = args[0];
var job_obj = Activator.CreateInstance(job_type);
DTO dto = (DTO)job_obj;
// Prints "Hello I constructing from test body"
dto.construct_from_body("test body");
}
}
interface DTO {
public void construct_from_body(string body);
}
class Job : DTO
{
public Job() { }
public void construct_from_body(string body)
{
Console.WriteLine($"Hello I constructing from {body}");
}
}
CodePudding user response:
What is invalid?
Do you want to make the compiler fail with every void
handler?
One way to achieve this up to two parameters:
public class MapPostImplementations
{
struct Discard
{
}
public void MapPost<A, B, R>(string path, Func<A, B, R> handler)
{
// Ignore the Discard type arguments
}
public void MapPost<A, R>(string path, Func<A, R> handler)
=> MapPost<A, Discard, R>(path, (a, _) => handler(a));
public void MapPost<R>(string path, Func<R> handler)
=> MapPost<Discard, R>(path, _ => handler());
class ExampleWebController
{
public void InvalidHandler() { }
public bool ProcessNumber(int v) { return true; }
public bool ProcessString(string v) { return true; }
}
ExampleWebController controller = new ExampleWebController();
void Test()
{
MapPost<string, bool>("/api/foo", controller.ProcessString);
MapPost<int, bool>("/api/numberFoo", controller.ProcessNumber);
// does not compile
//MapPost("/api/bar", controller.InvalidHandler);
}
}
CodePudding user response:
As of 2022, it appears I can only check that it is "some kind of delegate" in the where constraint :-(
public void MapPost<TFunc>(string path, TFunc handler) where TFunc: Delegate