C# 方法解析在运行时无法按预期工作

C# Method resolution does not work as expected at runtime

我查看了 ,方法解析在我的实例中没有按预期工作。

我 JSON 进入一个方法,我想从中创建一个类型化对象,然后验证它。

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

验证器 class 看起来是这样的:

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);
    }
}

即使在运行时,typeUser,它也不会调用 ValidateAsync(User user) 方法,而是调用 ValidateAsync(Object model) 方法。

但是,如果 type 在编译时不是动态的,而是我这样做:

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

它正确地调用了 ValidateAsync(User user) 方法。

是否有适当的方法在编译时拥有动态类型,但在运行时已知,并让它调用预期的“更具体”的方法?

更新

将任何“未来的编码器”添加到 switch 声明中并不过分询问 imo,因为无论如何他们都会在那个 class 添加他们的新 ValidateAsync(NewModel model) 方法.使用 dynamic 更符合我希望代码的方式,因为它不会用可能越来越大的 switch 语句使代码膨胀。但是,我担心性能影响。所以我 运行 Postman runner 使用 switch 语句(仅 User 或默认值)250 次,使用 dynamic 250 次。性能差异可以忽略不计。

带开关的平均响应时间:2.668ms

动态平均响应时间:2.816ms

因此,我将采用 dynamic 解决方案。谢谢!

重载解析发生在编译时,而不是运行时。 var model = JsonConvert.DeserializeObject(json, type); 创建的 model 将是 object 类型,因此编译器预计会 select ValidateAsync(Object model) 重载。

您可以尝试使用 dynamic 进行后期绑定(运行时)解析:

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

但请注意,它会带来一些性能成本。

另一种选择是 type testing 和铸造。例如,模式匹配可以如下所示:

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

您考虑的方法解析类型发生在编译时。

如果您想在 运行 时解决该方法,您必须自己编写代码,例如

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