Reputation: 8270
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?
UPDATE
Having any "future coder" add to the switch
statement was not too much of an ask imo, since they would be in that class adding their new ValidateAsync(NewModel model)
method anyways. Utilizing dynamic
was more along the lines of how I would like the code to be as it would not bloat the code with a possibly larger and larger switch
statement. But, I was worried about performance impact. So I ran a Postman runner 250 times with the switch
statement (just User
or default) and 250 times with dynamic
. The differences in performance was negligible.
Average response time with switch: 2.668ms
Average response time with dynamic: 2.816ms
So, I'm going to go with the dynamic
solution. Thanks!
Upvotes: 1
Views: 103
Reputation: 141835
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)
}
Upvotes: 1
Reputation: 52240
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);
}
Upvotes: 1