I think everyone knows that strings ( System.String ) are immutable in nature. Therefore, often working with methods such as string.ToUpper() and others, creates a new object that is almost identical to the previous one.

I don’t even want to find out the reasons for this, I clearly have a smaller mind than the guys who invented such a wrapper over the Char array, but you can still change the lines, at least through pointers.

Wrote such an expanding method:

 public static unsafe String ToUpperUnsafe ( this String value ) { fixed ( Char* arrChr = value ) { for ( var i = 0 ; i < value.Length ; ++i ) { var temp = Char.ToUpper( value[ i ] ); arrChr[ i ] = temp; } } return value; } 

As you can see, one object is accepted as input, changes and returns without cloning. The question is how safe it is. I looked through the source code of the original method, there are a lot of things that I did not understand, because of this, the thought arose that in certain situations it might not work.

ps By the way, the vanilla method works faster, but this one wins in the memory.

    3 answers 3

    So you can not do.

    The point is that the whole framework assumes that strings are immutable. Therefore, for example, if you place a line in a HashSet , and then change it, you will not be able to delete it from there (and along with you other pieces of the program that are far from you and do not know that you broke the line).

    The sorting method, which does not take into account that it can replace the value from under its nose, has the right to loop infinitely or fly out if the wrong index is accessed.

    Imagine what happens if the line you break is interned. Then everyone who had the string constant "abc" , suddenly without warning will receive the string constant "ABC" :

     string lo = "abc", hi = "ABC"; string villain = "abc"; villain.ToUpperUnsafe(); Console.WriteLine(lo == hi); // true 

    Imagine also that you break a string that is the name of a type. What happens when you try to apply reflection?

    In short, your method introduces undefined behavior into the language, the absence of which favorably distinguished C # from C ++.

    All this confusion, which can be arranged by one “small” optimization, is absolutely not worth the benefit of a few microseconds.

    • completely out of my head that the lines are interned, thanks) - anweledig
    • Strings are not fixed, as it seems. At least, the old implementation of StrungBuilder (before .net 4) used exactly the variable string. So probably something can be done with the internal integrity of the string. Its external immutability is much more important. - Qwertiy
    • @Qwertiy: Even if this is so, it’s one thing a local, internal object, about which language developers know that it is with him that you can make a hack. And another thing is an object that came from no one where it came from, and it is not known who and how still uses it. - VladD
    • @VladD, yes. I meant that it is safe to change the string only while it is guaranteed to be created by you. And, perhaps, additional crutches will be needed to preserve internal integrity. But as soon as the line got into the external code, or if it came from it, it cannot be changed. - Qwertiy
    • @Qwertiy: And in view of the inning, the fact that the string did not come from external code is not at all obvious. Since the compiler has the right to consider strings unchanged, we can never know whether we cheated or not. For example, he can zainlaynit our method, in which Upcase is called, and rearrange the operators (the string is considered unchanged for him!). Only a language developer can be one hundred percent sure that the string is independent, and it can be “spoiled”. - VladD

    The question is how safe it is.

    Yes, generally unsafe.

    I think everyone knows that strings (System.String) are immutable in nature. ... I don't even want to find out the reasons for this.

    In vain you do not want. Imagine everything written in literals. These are numbers. In VB more dates. All these are value types.

     int x = 50; x.Add(10); // Ну представим, что такой метод есть int y = 50; // Ну ты же не ждёшь, что теперь y равен 60? 

    Similarly with strings:

     string s = "abc"; s.ToUpper(); string t = "abc"; // Упс.. Твоя реализация сделает t = "ABC" 

    In my opinion, this alone is enough to never use your method.

    And now, why is the reference type? Yes, this is just an optimization - no need to copy huge lines with each transfer. We simply do not change the original, so semantically there is no difference between value and reference. But if we want to change, then we need to create a new line.

      You just invented the bike :), using unsafe, instead of the class StringBuilder , created just to represent the variable strings.

      • I am aware of this class, at the moment I am interested in one object against two and the safety of this method, and not expediency) - anweledig