Home > Enterprise >  Is it possible to infer this generic type, for type-safe callback?
Is it possible to infer this generic type, for type-safe callback?

Time:03-28

Is there a way to get rid of the CS0411 error below, and not have to explicitly state the type? Also do not want to have to use reflection.

var router = new ExampleRouter();
var controller = new ExampleWebController();

// compiles, but not elegant
router.MapPost<string>("/api/bar", controller.ProcessString);

// error CS0411: can't infer type
router.MapPost("/api/foo", controller.ProcessString);

class ExampleWebController {
    public ExampleWebController() { }
    public bool ProcessNumber(int v) { return true; }
    public bool ProcessString(string v) { return true; }
}

class ExampleRouter {
    public ExampleRouter() { }
    public void MapPost<TBody>(string path, Func<TBody, bool> handler) {
        // Save typeof(TBody), since TBody will actually be a class type we
        // will construct for each callback
        var body_type = typeof(TBody);
    }
}

CodePudding user response:

Yep, as someone's mentioned in comments one solution is to pass in the data as a parameter:

public void MapPost<TBody>(string path, Func<TBody, bool> handler, Tbody data) {

   object dataType = data.GetType();

}

CodePudding user response:

The reason your code is "inelegant" as you've said, is because the order of your generic arguments specifies an input type (TBody) and an output type (bool). However, in your calls to MapBody, you are only providing methods that return boolean results, so that the compiler doesn't know what to use for the value of TBody.

This is the origin of the CS0411 error you are receiving. The only way around it is to provide a generic type argument at the point of call.

This is why this code works, and should be what you use going forward:

var router = new ExampleRouter();
var controller = new ExampleWebController();

// compiles, but not elegant
router.MapPost<string>("/api/bar", controller.ProcessString);

CodePudding user response:

A bit of a self answer here. If I change it to this, the MapPost() code looks elegant, which was my goal. HOWEVER, I have lost some compile time checking -- for example anything can be passed in as a "handler". I will post a new question on how I refine this.

var router = new ExampleRouter();
var controller = new ExampleWebController();

// We will have to do runtime validation that controller.ProcessString is a
// legal callback (which isn't ideal, but still fine).
// An improvement would be to add some kind of generic constraints?
router.MapPost("/api/foo", controller.ProcessString);

class ExampleWebController {
    public ExampleWebController() { }
    public bool ProcessNumber(int v) { return true; }
    public bool ProcessString(string v) { return true; }
}

class ExampleRouter {
    public ExampleRouter() { }
    public void MapPost<TFunc>(string path, TFunc handler) {
        var func_type = typeof(TFunc);
        Console.WriteLine(func_type);  // Prints "System.Func"
        var args = func_type.GetGenericArguments();
        foreach (var arg in args) {
            // Prints "System.String", "System.Boolean"...awesome
            Console.WriteLine(arg);
        }
    }
}
  • Related