Home > front end >  C# Method resolution does not work as expected at runtime
C# Method resolution does not work as expected at runtime

Time:04-24

I looked at https://stackoverflow.com/a/5174773/787958 and the method resolution is not working as expected in my instance.

I have JSON coming into a method that I want to create a typed object from and then validate it.

var type = Type.GetType($"{Namespace.Models}.{typeName.FirstCharToUpper()}");
var model = JsonConvert.DeserializeObject(json, type);
var validator = new Validator();
var isValid = await validator.ValidateAsync(model);

The Validator class looks as such:

public class Validator : IValidator
{
    public Task<Boolean> ValidateAsync(Object model) { return Task.FromResult(true); }

    public Task<Boolean> ValidateAsync(User user)
    {
        if (user.Id == null || user.Id == Guid.Empty)
            return Task.FromResult(false);

        if (String.IsNullOrWhiteSpace(user.Name))
            return Task.FromResult(false);

        return Task.FromResult(true);
    }
}

Even though at runtime, type is User, it does not call the ValidateAsync(User user) method, instead it calls ValidateAsync(Object model) method.

But, if the type is not dynamic at compile time and instead I do:

var model = JsonConvert.DeserializeObject<User>(json);

It properly calls the ValidateAsync(User user) method.

Is there a proper way to have a dynamic type at compile time, but known at runtime, and have it call the expected "more specific" method?

CodePudding user response:

The type of method resolution you're thinking of happens at compile time.

If you want to resolve the method at run time you have to write the code for it yourself, e.g.

public Task<Boolean> ValidateAsync(Object model)
{
    return (model is User) ? ValidateAsync((User)model) : Task.FromResult(true);
}

CodePudding user response:

Overload resolution happens at the compile time, not in the runtime. model created by var model = JsonConvert.DeserializeObject(json, type); will be of object type so compiler will expectedly select ValidateAsync(Object model) overload.

You may try using dynamic for late bound (runtime) resolution:

dynamic model = JsonConvert.DeserializeObject(json, type);
var validator = new Validator();
var isValid = await validator.ValidateAsync(model);

But note that it comes with some performance cost.

Another option is type testing and casting. For example with pattern matching can look like this:

var isValid = model switch
{
    User user => await validator.ValidateAsync(user),
    _ =>  await validator.ValidateAsync(model)
}
  • Related