Skip to content

Instantly share code, notes, and snippets.

@plamentotev
Last active October 30, 2018 21:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plamentotev/9767a8fe3516584de6d3 to your computer and use it in GitHub Desktop.
Save plamentotev/9767a8fe3516584de6d3 to your computer and use it in GitHub Desktop.

На упражненията стана въпрос за String.Join и реализирахме нещо подобно. Интересно е да видим изходния код на метода, написан от Miscrosoft 😄

public static String Join(String separator, params Object[] values) {
    if (values==null)
        throw new ArgumentNullException("values");
    Contract.EndContractBlock();

    if (values.Length == 0 || values[0] == null)
        return String.Empty;

    if (separator == null)
        separator = String.Empty;

    StringBuilder result = StringBuilderCache.Acquire();

    String value = values[0].ToString();
    if (value != null)
        result.Append(value);

    for (int i = 1; i < values.Length; i++) {
        result.Append(separator);
        if (values[i] != null) {
            // handle the case where their ToString() override is broken
            value = values[i].ToString();
            if (value != null)
                result.Append(value);
        }
    }
    return StringBuilderCache.GetStringAndRelease(result);
}

Няколко интересни момента.

Ако values е празен масив (с дължина нула - values.Length == 0) се връща празен символен низ. values[0] == null ще го оставим за по-надолу.

if (values.Length == 0 || values[0] == null)
    return String.Empty;

В такъв случай масива съдържа поне един елемент, който се добавя към резултата:

String value = values[0].ToString();          
if (value != null)
    result.Append(value);

Още един интересен момент. Типа на result не е String, а StringBuilder. Защо се ползва StringBuilder, а не String може да прочетете тук Накратко - String e immutable клас (https://en.wikipedia.org/wiki/Immutable_object). Това означава, че когато конкатенирате два символни низа, се създава трети. Ако обединявате множество низове в цикъл, какъвто е нашият случай, е по-ефективно да се използва StringBuilder.

След това има следния цикъл:

for (int i = 1; i < values.Length; i++) {
    result.Append(separator);
    if (values[i] != null) {
        // handle the case where their ToString() override is broken
        value = values[i].ToString();
        if (value != null)
            result.Append(value);
    }
}

Както направихме и на упражненията, разделителя се слага преди елемента (само че няма такъв преди първия елемент).

Освен това не се създава инстанция на StringBuilder, а се взима от кеш(макар това да не е съвсем кеш в смисъла, който може би сте срещали другаде):

StringBuilder result = StringBuilderCache.Acquire();

а след приключване на работата се освобождава:

return StringBuilderCache.GetStringAndRelease(result);

Създаването и инициализирането на обекти (особено на някой обекти, като нишки, връзка с база данни и тн) отнема време. За това в някой случай е по-добре да се преизпълват съществуващи инстанции на класа. За тази концепция можете да прочетете тук. Между другото, ако искате да видите изходния код на StringBuilderCache, просто кликнете на името - това е линк.

Обърнете внимание и че проверяват values за null

if (values==null)
    throw new ArgumentNullException("values");

Това, както и извикването на Contracts класа, е част от концепция, която е обяснена тук и най-вероятно ви е позната от ООП.

И стигнахме до "по-надолу". Интересно, че ако някой елемент от values е null, то той просто не се добавя към резултата. С изключение на първият елемент - ако той е null се връща празен низ. Интересно каква е логиката зад това. Аз лично не се сещам. Както се казва помагайте :)

Виждате колко интересни неща могат да се научат, ако човек порови дори в един наглед "прост" метод - обединяването на елементите на масив в символен низ.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment