为什么字符串被密封

时间:2016-03-11 23:00:09

标签: c# .net

我很好奇为什么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等,以及名称,评论,都是其性质的字符串。我们将它们作为数据库中的字符串,或者在网页上的文本框中键入字符串,或者通过条形码扫描仪等进行封装。

拥有具有特定功能的字符串而不是发明多个类,或多或少地做同样的事情,这将是非常好的,更安全和更优雅。

3 个答案:

答案 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)
{

}