C# 6 中的字符串插值和重写的 ToString()
String interpolation in C# 6 and overridden ToString()
给出以下 类:
public abstract class ValueBase
{
public new abstract string ToString();
}
public class EmailAddress : ValueBase
{
public MailAddress MailAddress { get; }
public EmailAddress([NotNull] string address)
{
MailAddress = new MailAddress(address);
}
public override string ToString()
{
return MailAddress.Address;
}
}
为什么:
var email = new EmailAddress("joe@bloggs.com");
string emailString1 = $"{email}";
string emailString2 = email.ToString();
return 类型名称的字符串 (Namespace.EmailAddress
),而不是覆盖的 ToString 方法 (joe@bloggs.com
)?
string emailString1 = $"{email}"; //call the Object.ToString() method
string emailString2 = email.ToString();//call your overrided ValueBase.ToString() method
其实$""最终都是使用了classStringBuilder中的一个内部方法。
StringBuilder.AppendFormatHelper(IFormatProvider 提供程序、字符串格式、ParamsArray 参数)
关键代码:
object obj = args[index3];
//... bilibili About On Line 1590
else if (obj != null)
str = obj.ToString();// So it use the object.ToString()
插值按预期工作,因为您的 类 没有 覆盖 Object.ToString()
。 ValueBase
定义了一个 new 方法 隐藏 Object.ToString
而不是覆盖它。
只需从 ValueBase
中删除 ToString
。在这种情况下,Email.Address
将正确覆盖 Object.ToString
,插值将 return 获得所需的结果。
具体来说,将 ValueBase 更改为:
public abstract class ValueBase
{
}
制作测试代码
var email = new EmailAddress("joe@bloggs.com");
string emailString1 = $"{email}";
return joe@bloggs.com
更新
正如人们建议的那样,可以添加基础 ToString()
方法以强制实施者在其 类 中实施自定义 ToString
方法。这可以通过定义 abstract override
方法来实现。
public abstract class ValueBase
{
public abstract override string ToString();
}
嗯,$"{email}"
字符串自动转换为 string.Format("{0}", email)
并且此方法的第二个参数是 params object[]
类型。因此它在调用 ToString()
方法之前将所有值向上转换为 object
。在您的代码中,您只需将此方法替换为 ValueBase
class 中的新方法,并且 EmailAddress
class 中的 override
关键字实现此抽象方法而不是原始对象的一.
如果将第二个值显式转换为对象,则可以轻松地对其进行测试:
var email = new EmailAddress("joe@bloggs.com");
string emailString1 = $"{email}";
string emailString2 = ((object)email).ToString();
正如您现在看到的那样 emailString2
returns typename 也是如此。您可以从抽象 class 中删除 ToString()
方法,让 EmailAdress
class 实现对象的 ToString()
或在抽象 class 中实现它。例如:
public abstract class ValueBase
{
// overrides object's ToString()
public override string ToString()
{
return base.ToString();
}
}
public class EmailAddress : ValueBase
{
...
// overrides ValueBase's ToString()
public override string ToString()
{
return MailAddress.Address;
}
}
使用这个新代码,输出符合预期:
joe@bloggs.com
joe@bloggs.com
首先,躲ToString
是自讨苦吃,千万别做; string.Format("{0}", email)
或 $"{email}
打印出的内容与 email.ToString()
.
不同,这很令人困惑
其次,emailString1
和emailString2
不可能和你说的一样。 email.ToString()
的输出是"joe@bloggs.com"
,$"{email}"
的输出是"{namespace}.EmailAddress"
.
为什么不同?这是因为你隐藏ToString
在ValueBase
。 EmailAddress.ToString
类型的调用(通过 EmailAddress
类型引用的调用)将调用 ToString
的新实现,但 Object.ToString
调用(通过 object
typed reference) 将调用 Object
中的实现; $"{email}"
等同于 string.Format("{0}", email)
在道德上等同于 string.Format("{0}", (object)mail)
所以你实际上是在调用 ToString
形式的对象类型引用;
您需要做的是 覆盖 ToString
并且您将获得预期的行为:
public abstract class ValueBase
{
public override abstract string ToString();
}
任何对 EmailAddress.ToString
的调用,无论引用的类型如何,都将调用覆盖的实现。
请注意,您似乎将 new 和 override 混为一谈:
Why does ... return a string of the type name (Namespace.EmailAddress)
, not the overridden ToString
method (joe@bloggs.com
)?
您没有覆盖 ToString
,而是隐藏它。要查看 new
和 override
之间的区别,请阅读 this SO question。
给出以下 类:
public abstract class ValueBase
{
public new abstract string ToString();
}
public class EmailAddress : ValueBase
{
public MailAddress MailAddress { get; }
public EmailAddress([NotNull] string address)
{
MailAddress = new MailAddress(address);
}
public override string ToString()
{
return MailAddress.Address;
}
}
为什么:
var email = new EmailAddress("joe@bloggs.com");
string emailString1 = $"{email}";
string emailString2 = email.ToString();
return 类型名称的字符串 (Namespace.EmailAddress
),而不是覆盖的 ToString 方法 (joe@bloggs.com
)?
string emailString1 = $"{email}"; //call the Object.ToString() method
string emailString2 = email.ToString();//call your overrided ValueBase.ToString() method
其实$""最终都是使用了classStringBuilder中的一个内部方法。
StringBuilder.AppendFormatHelper(IFormatProvider 提供程序、字符串格式、ParamsArray 参数)
关键代码:
object obj = args[index3];
//... bilibili About On Line 1590
else if (obj != null)
str = obj.ToString();// So it use the object.ToString()
插值按预期工作,因为您的 类 没有 覆盖 Object.ToString()
。 ValueBase
定义了一个 new 方法 隐藏 Object.ToString
而不是覆盖它。
只需从 ValueBase
中删除 ToString
。在这种情况下,Email.Address
将正确覆盖 Object.ToString
,插值将 return 获得所需的结果。
具体来说,将 ValueBase 更改为:
public abstract class ValueBase
{
}
制作测试代码
var email = new EmailAddress("joe@bloggs.com");
string emailString1 = $"{email}";
return joe@bloggs.com
更新
正如人们建议的那样,可以添加基础 ToString()
方法以强制实施者在其 类 中实施自定义 ToString
方法。这可以通过定义 abstract override
方法来实现。
public abstract class ValueBase
{
public abstract override string ToString();
}
嗯,$"{email}"
字符串自动转换为 string.Format("{0}", email)
并且此方法的第二个参数是 params object[]
类型。因此它在调用 ToString()
方法之前将所有值向上转换为 object
。在您的代码中,您只需将此方法替换为 ValueBase
class 中的新方法,并且 EmailAddress
class 中的 override
关键字实现此抽象方法而不是原始对象的一.
如果将第二个值显式转换为对象,则可以轻松地对其进行测试:
var email = new EmailAddress("joe@bloggs.com");
string emailString1 = $"{email}";
string emailString2 = ((object)email).ToString();
正如您现在看到的那样 emailString2
returns typename 也是如此。您可以从抽象 class 中删除 ToString()
方法,让 EmailAdress
class 实现对象的 ToString()
或在抽象 class 中实现它。例如:
public abstract class ValueBase
{
// overrides object's ToString()
public override string ToString()
{
return base.ToString();
}
}
public class EmailAddress : ValueBase
{
...
// overrides ValueBase's ToString()
public override string ToString()
{
return MailAddress.Address;
}
}
使用这个新代码,输出符合预期:
joe@bloggs.com
joe@bloggs.com
首先,躲ToString
是自讨苦吃,千万别做; string.Format("{0}", email)
或 $"{email}
打印出的内容与 email.ToString()
.
其次,emailString1
和emailString2
不可能和你说的一样。 email.ToString()
的输出是"joe@bloggs.com"
,$"{email}"
的输出是"{namespace}.EmailAddress"
.
为什么不同?这是因为你隐藏ToString
在ValueBase
。 EmailAddress.ToString
类型的调用(通过 EmailAddress
类型引用的调用)将调用 ToString
的新实现,但 Object.ToString
调用(通过 object
typed reference) 将调用 Object
中的实现; $"{email}"
等同于 string.Format("{0}", email)
在道德上等同于 string.Format("{0}", (object)mail)
所以你实际上是在调用 ToString
形式的对象类型引用;
您需要做的是 覆盖 ToString
并且您将获得预期的行为:
public abstract class ValueBase
{
public override abstract string ToString();
}
任何对 EmailAddress.ToString
的调用,无论引用的类型如何,都将调用覆盖的实现。
请注意,您似乎将 new 和 override 混为一谈:
Why does ... return a string of the type name
(Namespace.EmailAddress)
, not the overriddenToString
method (joe@bloggs.com
)?
您没有覆盖 ToString
,而是隐藏它。要查看 new
和 override
之间的区别,请阅读 this SO question。