覆盖 ToString() 在抽象 class (.net-core 3.1) 中不起作用

Override ToString() is not working in abstract class (.net-core 3.1)

将对象插入字符串时(主要用于日志目的),需要显式序列化,否则得到的是:

<ProjectName>.<Class>

或者在我的情况下

ConsoleApp1.Program+Person

所以我制作了一个非常简单的控制台应用程序作为 PoC 来解决这个问题。

在这个 PoC 中,我有一个抽象基础 class,它只用 JsonSerializer 覆盖 ToString 方法,所以我不需要每次想要 log/ConsoleWrite 我的对象时都进行序列化。

    public abstract class BaseModel
    {
        public override string ToString()
        {
            return JsonSerializer.Serialize(this);
        }
    }

这个抽象 class 应该被我所有​​的模型继承。这是整个控制台应用程序

        static async Task Main(string[] args)
        {
            var a = new Person() { Name = "John", Lastname = "Doe" };
            Console.WriteLine($"Hi, {a}.");
            Console.ReadKey();
        }

        public class Person : BaseModel
        {
            public string Name { get; set; }
            public string Lastname { get; set; }
        }

运行 ConsoleWrites

上面的代码
Hi, {}.

为什么是空的?

当我在抽象方法中将 Quickwatch 放在 this 上时,我可以看到属性已正确填充。

为什么会这样?

将您的序列化代码更改为(假设您使用的是 System.Text.Json):

public abstract class BaseModel
{
    public override string ToString()
    {
        return JsonSerializer.Serialize(this, this.GetType());
    }
}

您在基础 class 中使用通用 JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions) 重载,因此在编译期间通用参数 TValue 被替换为您的 BaseModel class,其中没有属性,基本上以正在执行 JsonSerializer.Serialize<BaseModel>(this) 调用结束。

您使用的 .NET Core json 序列化程序方法是通用的,如下所示:

public static string Serialize<TValue> (TValue value,
    System.Text.Json.JsonSerializerOptions options = default);

根据设计,它在序列化时仅考虑 TValue 中的属性,并且由于您是从摘要 class 中调用它的,使用 this,这当然会是抽象 class 类型的,它只考虑抽象 class.

中的属性

基本上你的电话被推断为

return JsonSerializer.Serialize<BaseModel>(this);

幸运的是,它很容易修复,只需切换到调用非泛型方法即可:

return JsonSerializer.Serialize(this, GetType());

现在它使用有关您实际调用它的类型的运行时信息,而不是抽象 class,并且应该正确地序列化您的后代类型的属性。