System.String - 为什么不实现无参数构造函数?

emp*_*mpi 26 .net string constraints

我想问一下System.String不包含无参数构造函数背后的想法是什么.

因此,当存在new()约束时,不能使用此类型.

UPDATE

为什么你认为新的string()是无用的,例如new int()没用.我真的看不出差异.我真的希望能够对字符串使用new()约束,因为我期待的是String.Empty.

UPDATE2

我知道int是一个值类型,所有值类型都有默认的无参数构造函数.我指的是@John Saunders的回答(和类似的答案),说明新的String()基本上没有做任何有用的事情.那么,如果新的String()并不意味着什么对新的int()有用呢?我也明白,值类型具有默认的无参数构造函数非常重要.更重要的是我认为字符串有一个默认的无参数构造函数真的很好.缺乏无参数构造函数对我来说意味着如果没有将初始化它的参数,对象就不会存在.在我看来,字符串不需要任何参数,因为它可能是空的.我问了这个问题,因为我想知道是否有一些重要的原因让字符串没有无参数构造函数,或者它只是设计或者其他.

UPDATE3

我想这将是最后一次更新,因为它看起来更像博客文章而非问题.在java中,字符串也是不可变的,新的String()是完全合法的.但是,无参数构造函数的文档说:

初始化新创建的String对象,使其表示空字符序列.请注意,由于字符串是不可变的,因此不必使用此构造函数.

UPDATE4

好的,最后更新;)我必须同意John Saunders.我使用的是具有new()约束的代码,它适用于自定义类.然后,我的同事需要更改int的代码,这没关系.然后将其更改为字符串,我们遇到了问题.当我想到它时,我想我们正在使用的代码需要改变以反映我们需要标量类型而不是具有无参数构造函数的类.所有这一切,我仍然认为你可以编写新的int()并且你无法编写新的string()(是的,我知道int是一种值类型;))有点不一致.谢谢你的所有答案!

在此先感谢您的帮助.

Joh*_*ers 25

如果你可以使用

string s = new string();
Run Code Online (Sandbox Code Playgroud)

你会怎么做?字符串是不可变的.


有些读者认为我说无参数字符串构造函数是没用的.那不是我要表达的意思.我的意思是从这样的构造函数创建的空字符串在其余代码中将是无用的.

请记住OP说他想做的事情:

public void SomeMethod<T>() where T : new()
{
    var t = new T();
    // Do _what_ now?
}

// Call:
SomeMethod<string>();
Run Code Online (Sandbox Code Playgroud)

t在构建之后,我看不出你能做些什么.

  • @John:new String()应该合理地返回String.Empty.我已经多次被烧了,因为我想把一个字符串传递给一个泛型方法`DoSomething <T>(T t),其中T:new()`,但我不能使用字符串因为它们没有默认构造函数. (17认同)
  • @Joren:不,这是答案.它没有无参数构造函数,因为它在不可变类型中没有任何意义. (3认同)
  • 那么你永远不会使用String.Empty吗? (2认同)
  • @Joe Gauterin - 我不认为Saunders在谈论String.Empty.他说,为字符串类设置无参数构造函数是没有意义的.您可以设置默认值string.empty或null. (2认同)
  • @JonH:显然,拥有一个无参数构造函数是有意义的,因为提问者有一个用例.默认值所有类类型都为null,而不是String.Empty没有帮助. (2认同)

Jul*_*iet 11

为什么你认为新的string()是无用的,例如new int()没用.

让我们回到基础,讨论参考和价值类型.

当你创建一个int,long,point或者其他什么时,值类型被分配在堆栈上 - 所以int在堆栈上保留4个字节,long是8个字节,依此类推.为值类型保留的堆栈空间为零 - 它不可能引用堆栈上的值类型地址并获得null.因此,值类型的默认构造函数可能更多地来自堆栈分配中的怪癖而不是有用性(也许MS的某个人可以提供更多的洞察力).

在任何情况下,我认为System.String缺乏默认构造函数,因为糟糕的API设计.

不可变对象 - 特别是可枚举 - 几乎总是暴露默认构造函数来实例化一个空集合.

我认为微软有良好的意图:最好使用""或者String.Empty只要你需要一个空字符串,因为它们是实习的,而且不是new String()每次都有用的东西- 但是我认为它是微软拯救开发者的方式.从他们自己".

(感谢微软,我很感激你的家长式手持,但我完全有能力照顾自己.如果我不想创建同一个对象的多个实例,我会像我一样缓存它带有默认构造函数的bagillion其他类型.)

现在,您需要将没有默认构造函数的对象视为其他所有内容的特殊情况.改写

public void DoSomething<T>() where T : new() { ... }
Run Code Online (Sandbox Code Playgroud)

有两种方法:

public void DoSomething<T>() where T : new() { DoSomething(() => new T()); }

public void DoSomething<T>(Func<T> constructor) { }
Run Code Online (Sandbox Code Playgroud)

代码的客户端应该决定自己调用哪个函数.


现在看看上面代码的人可能会问你为什么要将构造函数而不是实际对象传递给方法,即

public void DoSomething<T>(T obj) { ... }
Run Code Online (Sandbox Code Playgroud)

可能有原因,例如,如果不保证调用构造函数方法.我使用复杂的winform应用程序,其中单击按钮或菜单项会弹出一个表单 - 或者,如果表单已经打开,我们将重点关注它.所以我们有类似的东西:

public T ShowForm<T>(Func<T> constructor) where T : Form
{
    T res = default(T);
    foreach(Form f in Application.OpenForms)
    {
        if (f is T)
        {
            res = (T)f;
            break;
        }
    }

    if (res == null)
        res = constructor();

    res.Focus();
    return res;
}
Run Code Online (Sandbox Code Playgroud)

我们无法使用新约束,因为某些形式具有非默认构造函数,因此上述策略最终确实很好并且为我们节省了创建大量工厂类的麻烦.