1. 概述
今天在写代码的过程都遇到了一个提示:
redundant 'object.tostring()' call
截图如下:
IDE的意思是可以去除 ToString()
的调用, 为什么会有这个提示呢?
查看 MakeCallInfo
这个类发现覆写了 ToString()
方法. 那么是不是只要有 ToString()
方法就会有这个提示呢?
2. 测试
2.1 不添加 ToString()
方法
编写如下代码:
namespace DevConsoleApp {
class Program {
static void Main(string[] args) {
Person p = new Person();
p.Name = "张三";
p.Age = 13;
Console.WriteLine(p);
Console.WriteLine(p.ToString());
Console.WriteLine($"this is {p}");
Console.WriteLine($"this is {p.ToString()}");
Console.ReadKey();
}
}
class Person {
public string Name;
public int Age;
}
}
Person
类没有继承覆写 ToString()
方法, 在 Main
方法中的四种写法中, IDE在最后的一种写法中做了提示:
因为 Person
类没有 ToString()
方法, 实际调用的是 object.ToString()
方法, 所以这里会提示.
运行结果如下:
2. 添加 ToString()
方法
修改代码如下:
namespace DevConsoleApp {
class Program {
static void Main(string[] args) {
Person p = new Person();
p.Name = "张三";
p.Age = 13;
Console.WriteLine(p);
Console.WriteLine(p.ToString());
Console.WriteLine($"this is {p}");
Console.WriteLine($"this is {p.ToString()}");
Console.ReadKey();
}
}
class Person {
public string Name;
public int Age;
public string ToString() {
return $"{nameof(Name)}: {Name}, {nameof(Age)}: {Age}";
}
}
}
这种修改以后, IDE 在输出的时候没有再提示 redundant 'object.tostring()' call
, 截图如下:
但是, 此时的 ToString()
方法会有提示:
因为新添加的方法和父类的方法同名, 所以这里会提示让你确认这是覆写的父类方法还是新增的方法.
如果不按照它的提示, 直接运行会怎样?
运行结果可以看出, 第一个输出不是 ToString()
的格式字符串, 这说明编译器默认该方法为 新方法, 和 添加 new
关键字一致.
2.3 添加覆写方法
将2.2 的 new
改为 override
, 即覆写父类的 ToString()
方法:
namespace DevConsoleApp {
class Program {
static void Main(string[] args) {
Person p = new Person();
p.Name = "张三";
p.Age = 13;
Console.WriteLine(p);
Console.WriteLine(p.ToString());
Console.WriteLine($"this is {p}");
Console.WriteLine($"this is {p.ToString()}");
Console.ReadKey();
}
}
class Person {
public string Name;
public int Age;
public override string ToString() {
return $"{nameof(Name)}: {Name}, {nameof(Age)}: {Age}";
}
}
}
此时, 输出部分 IDE 扔会提示 redundant 'object.tostring()' call
, :
运行结果呢?
从输出结果看, 第一种和第二种输出结果是一致的. 但是为什么第二种不提示 第四种提示呢?
3. 查看源码
第一种输出 Console.WriteLine(p);
其代码实现如下:
public static void WriteLine(object value)
{
Console.Out.WriteLine(value);
}
public virtual void WriteLine(object value)
{
if (value == null)
this.WriteLine();
else if (value is IFormattable formattable)
this.WriteLine(formattable.ToString((string) null, this.FormatProvider));
else
this.WriteLine(value.ToString());
}
其实最终还是调用了 ToString()
方法.
剩下的输出其实都是调用了 Console.WriteLine(string value)
方法, 如下:
public static void WriteLine(string value)
{
Console.Out.WriteLine(value);
}
public virtual void WriteLine(string value)
{
if (value == null)
{
this.WriteLine();
}
else
{
int length1 = value.Length;
int length2 = this.CoreNewLine.Length;
char[] chArray = new char[length1 + length2];
value.CopyTo(0, chArray, 0, length1);
switch (length2)
{
case 1:
chArray[length1] = this.CoreNewLine[0];
break;
case 2:
chArray[length1] = this.CoreNewLine[0];
chArray[length1 + 1] = this.CoreNewLine[1];
break;
default:
Buffer.InternalBlockCopy((Array) this.CoreNewLine, 0, (Array) chArray, length1 * 2, length2 * 2);
break;
}
this.Write(chArray, 0, length1 + length2);
}
}
第二种输出格式 是在传参给 WriteLine
方法时, 已经进行了格式化处理, 传入的就是一个 string字符串. 即:
- 如果不带
ToString
方法, 调用的是Console.WriteLine(object o)
方法 - 如果带
ToString()
方法, 调用的是Console.WriteLine(string value)
方法
所以第二种输出格式不会提示 Redundant 'object.tostring()' call
.
而第三四种输出 传入的参数是一个格式化的 string字符串, 内插值字符串.
对于内插值字符串, 官方文档:$ - 字符串内插 - C# 参考 | Microsoft Docs 的一段说明如下:
隐式转换和指定
IFormatProvider
实现的方式内插字符串有 3 种隐式转换:
- 将内插字符串转换为 String 实例,该类例是内插字符串的解析结果,其中内插表达式项被替换为结果的格式设置正确的字符串表示形式。 此转换使用 CurrentCulture 设置表达式结果的格式。
- 将内插字符串转换为表示复合格式字符串的 FormattableString 实例,同时也将表达式结果格式化。 这允许通过单个 FormattableString 实例创建多个包含区域性特定内容的结果字符串。 要执行此操作,请调用以下方法之一:
- ToString() 重载,生成 CurrentCulture 的结果字符串。
- Invariant 方法,生成 InvariantCulture 的结果字符串。
- ToString(IFormatProvider) 方法,生成特定区域性的结果字符串。
你还可使用 ToString(IFormatProvider) 方法,以提供支持自定义格式设置的 IFormatProvider 接口的用户定义实现。 有关详细信息,请参阅在 .NET 中设置类型格式一文中的使用 ICustomFormatter 进行自定义格式设置部分。
- 将内插字符串转换为 IFormattable 实例,使用此实例也可通过单个 IFormattable 实例创建多个包含区域性特定内容的结果字符串。
意思就是说, 内插值字符串直接传入对象的引用 会实际调用其 ToString()
方法, 所以会提示 Redundant 'object.tostring()' call
4. 总结
从上述分析中看出, 如果我们要覆写父类的方法就必须带上 override
关键字, 否则编译器会认为你写的是一个新的方法,即默认为 new
关键字.
评论区