我很好奇为什么System.String被密封了?
我知道,我可以做任何我不需要继承的事情,但仍然 - 为什么?
有很多类本质上是具有特定方法和属性的字符串。这些是标识符,电子邮件,姓名等。
面向对象的设计建议将功能封装在特定的类中。在这里我们有一种奇怪的情况,即最流行的对象框架中最可用的基本类型是不可扩展的。
谢谢。
编辑。
关于不变性的评论。在私有方法中隐藏所有与状态相关的东西很容易,并且允许子类具有对类数据的只读访问权。
// Safe inheritable immutable string (pseudocode).
class String
{
// Private state
private byte[] state;
private void EditState(byte[]) {}
// Protected read-only access to state
protected byte getReadOnlyData() {}
// Available to child classes overridable methods.
protected virtual getHashCode() {}
protected virtual xxx() {}
}
实际上,实际应用程序中的大多数对象都是字符串。所有这些连续出版物,ASIN,IMEI等,以及名称,评论,都是其性质的字符串。我们将它们作为数据库中的字符串,或者在网页上的文本框中键入字符串,或者通过条形码扫描仪等进行封装。
拥有具有特定功能的字符串而不是发明多个类,或多或少地做同样的事情,这将是非常好的,更安全和更优雅。
答案 0 :(得分:12)
有很多类本质上是具有特定方法和属性的字符串。这些是标识符,电子邮件,姓名等。
这个特定的用例可以通过组合而不是继承来更好地处理,即:"电子邮件地址具有字符串表示"而不是"电子邮件地址是字符串" (因为电子邮件地址实际上是多个子字段的组合,当您使用SMTP时恰好具有简洁的字符串表示。)
另一点是String是一种基本类型 - 从int
派生出来是不合理的 - 为什么是一个字符串?如果要扩展String
的实施,您只需要从System.String
派生 - 例如,您想要覆盖其GetHashcode
实施 - 但是您的操作数量是多少可以想象,覆盖是非常有限的,那么为什么框架维护者需要支持这种情况呢?
正如@Steve在评论中所链接的那样,Eric Lippert撰写的这篇博文也解释了为什么许多类都是sealed
,特别是来自维护PoV:https://blogs.msdn.microsoft.com/ericlippert/2004/01/22/why-are-so-many-of-the-framework-classes-sealed/
最后,如果你真的想要自己的字符串行为(这很可能:你可以使用长度为前缀的字符串,以null结尾的字符串,在较大的字符串缓冲区中存在为定义范围的字符串,基于链表的字符串,一个以高效内存方式保存多个字符串的Trie,多种方法的混合,等等)你可以从头开始构建自己的实现 - 这些都不需要从System.String
派生出来。当然,你不能将它传递给一个需要String值的类,但这只是公平的,因为这些消费者可能依赖于System.String
的特定实现行为(例如运行时性能) ,不变性等)。
答案 1 :(得分:5)
字符串被密封主要是因为它是不可变的并且CLR广泛使用该特征(实习,跨域编组)。如果字符串不会被密封,那么所有CLR对字符串不变性的期望都不会花费一分钱。
答案 2 :(得分:1)
FYI“隐式运算符”是通过继承扩展密封类的替代方法。只要新类仅是强类型字符串。这些类将在需要字符串的地方可用...简化了用法
public class Email
{
string m_stringfrom; // no other fields
public static implicit operator string(Email email)
{
return email.m_stringfrom;
}
public static implicit operator Email(string email)
{
return new Email() {
m_stringfrom = email // only field in email !
};
}
}
void test()
{
Email work_email = "test@domain.com";
Display(work_email);
}
void Display( string toBeDisplayed)
{
}