Why doesn't System.String include a constructor capable of taking a IEnumerable<char>?

The expected behavior would be:

var foo = "hello";
var bar = new string(foo.Select(x => x));

Actual behavior:

Cannot convert from 'System.Collections.Generic.IEnumerable<char>' to 'char*'

If there is no obvious reason, I think it could be a nice pull request.

source: String.cs StringNative.cpp

  • 1
    Unfortunately, the only answer we can provide to "Why did {somebody} do {something} instead of {my way}?" is "You have to ask {somebody}". In this case, {somebody} would be Microsoft. – Adam Zuckerman Jul 6 '16 at 20:28
  • @AdamZuckerman maybe there is a public issue somewhere (I search on github without success) or a softies who talk about this on a blog post) – aloisdg moving to codidact.com Jul 6 '16 at 20:37
  • I am not aware of any discussion or blog about why this wasn't included. In addition to Robert Harvey's answer, you could also write an extension method to take an IEnumerable<char> as a parameter. I suspect the implementation won't be significantly different that presented in his answer. – Adam Zuckerman Jul 6 '16 at 20:44
  • @AdamZuckerman "I suspect the implementation won't be significantly different" So do I.I find the absence of this constructor not intuitive. thats all. – aloisdg moving to codidact.com Jul 6 '16 at 20:48

Since there is a constructor overload that takes an array of characters, this should work:

var bar = new string(foo.Select(x => x).ToArray());

Which pretty much eliminates the need for another constructor overload, as the proposed overload would essentially have to do the same thing.

Eric Lippert often discusses why certain features don't make it into the .NET Framework or the C# language. He says:

The answer is always the same: because no one ever designed, specified, implemented, tested, documented and shipped that feature. All six of those things are necessary to make a feature happen. All of them cost huge amounts of time, effort and money.

In other words, every feature must have benefits that exceed those costs, and the .NET Team decided in this instance that the extra constructor was not worth it.

Further Reading
Best way to convert IEnumerable to string?

| improve this answer | |
  • 2
    Which costs an additional allocation and memory copy compared to a native implementation for this, which for larger strings could be expensive. – CodesInChaos Jul 6 '16 at 20:33
  • Of course. But since it's not actually a string that is being passed... – Robert Harvey Jul 6 '16 at 20:34
  • So the answer would be that it doesn't exist because there is no need for it? Like a lot of features, I think this one would be convenient. – aloisdg moving to codidact.com Jul 6 '16 at 20:40
  • @aloisdg: I've added some clarification to my answer. – Robert Harvey Jul 6 '16 at 20:44
  • @RobertHarvey I know this quote and if is the final answer, I will implement it myself and submit it. For know, I wonder why. :) – aloisdg moving to codidact.com Jul 6 '16 at 20:45

This constructor takes an array of chars as its input. For your use case, you can simply:

var bar = new string(foo.Select(x => x).ToArray());

If you wanted a rationale, you could say that the lazy-loading behavior of the IEnumerable does not give you any added benefit here since you need to read the whole thing anyway to create the string. Whether you convert it to an array before you pass it, as my example does, or pass it an IEnumerable for the constructor to convert, the operations and performance should be almost the same.

| improve this answer | |
  • So why List<T> (or any other collection) has a constructor taking an IEnumerable<T>? – aloisdg moving to codidact.com Jul 6 '16 at 20:42
  • @aloisdg: List<T> already inherits from the IEnumerable<T> interface, making the constructor implementation trivial. – Robert Harvey Jul 6 '16 at 20:49
  • @RobertHarvey String inherits from IEnumerable<char>. I guess making the constructor is trivial too. – aloisdg moving to codidact.com Jul 6 '16 at 20:50
  • That's not IEnumerable<T>; it's IEnumerable<char>. There's a difference, and it's a material one. – Robert Harvey Jul 6 '16 at 20:51
  • @RobertHarvey True, but I don't see why it is a problem. – aloisdg moving to codidact.com Jul 6 '16 at 20:52

On the one hand we expect convenience, on the other strict OOP principles being applied. If you implement too many convenient overloads, you will soon be implementing a universal type converter in a string class. And then something else. I guess keeping things mean and lean and sticking to the single responsibility principle outweighed the need for more convenience. As others pointed out, there is not really an inconvenience in using ToArray on the argument. It is about putting responsibilities where they belong.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.