0

Прошу Вас помочь оптимизировать код вывода в textblock. Показать как правильно. Спасибо.

public void PrintCurrentlyPlaying(object sender, EventArgs e)
    {
        var sessionManager = GlobalSystemMediaTransportControlsSessionManager.RequestAsync().GetAwaiter().GetResult(); // получаем результат из Control Media Windows 10
        if (sessionManager != null) // если результат получен, то 
        {
            var currentSession = sessionManager.GetCurrentSession(); // возращаем сессию
            if (currentSession != null) // если сессия не пустая, то
            {
                var mediaProperties = currentSession.TryGetMediaPropertiesAsync().GetAwaiter().GetResult(); // в mediaProperties мы отправляем название воспроизведения и имя автора
                if (unknown_artist.IsChecked == true && dash_instead_text.IsChecked == false && mediaProperties.Artist == "Неизвестный исполнитель") // проверяем настройки приложения и выводим со словами
                    compocition_output.Text = $"Проигрывается: {mediaProperties.Title}";
                else
                {
                    if (unknown_artist.IsChecked == true && dash_instead_text.IsChecked == true && mediaProperties.Artist == "Неизвестный исполнитель") // иначе выводим без слов
                        compocition_output.Text = $"{mediaProperties.Title}";
                    else
                    {
                        if (dash_instead_text.IsChecked == true && mediaProperties.Artist != "")  
                            compocition_output.Text = $"{mediaProperties.Title} - {mediaProperties.Artist}";
                        else 
                        {
                            if (dash_instead_text.IsChecked == true)
                                compocition_output.Text = $"{mediaProperties.Title}";
                            else
                            {
                                if (mediaProperties.Artist != "")
                                {
                                    if (author_checkbox.IsChecked == true && compocition_checkbox.IsChecked == true)
                                        compocition_output.Text = $"Проигрывается: {mediaProperties.Title}, от автора: {mediaProperties.Artist}";
                                    else
                                    {
                                        if (author_checkbox.IsChecked == false && compocition_checkbox.IsChecked == true)
                                            compocition_output.Text = $"Проигрывается: {mediaProperties.Title}";
                                        else
                                        {
                                            if (author_checkbox.IsChecked == true && compocition_checkbox.IsChecked == false)
                                                compocition_output.Text = $"Автор воспроизведения: {mediaProperties.Artist}";
                                        }
                                    }
                                }
                                else
                                    compocition_output.Text = $"Проигрывается: {mediaProperties.Title}";
                            }
                        }
                    }
                }
            }
            else
                compocition_output.Text = "Упс... А музыка у нас закончилась!";
        }
        else
            compocition_output.Text = "Упс... А музыка у нас закончилась!";
        if (output_file_checkbox.IsChecked == true)
        {
            file_save(null, null); // сохраняем название в .txt файл
        }
}

Если будет возможно с комментариями.

aepot
  • 49,560
  • 1
    А что понимается под словом «оптимизировать»? Если уменьшить количество кода, то начните с устранения копипасты. Смотрите на повторяющиеся строки кода, обобщите их. Кстати, это WPF? – Артём Оконечников Jan 19 '21 at 18:15
  • Этот код работает? – aepot Jan 19 '21 at 18:17
  • Может стоило хотя бы написать, что вообще этот код делает? – Павел Ериков stand with Russia Jan 19 '21 at 18:23
  • @АртёмОконечников, да это WPF. Первое приложение. Без ООП, из-за не знания соответственно(видно по коду). Проблема еще тут в том, что я немного не понимаю, где копипаст. – Artem L. Jan 19 '21 at 19:48
  • @aepot Наверное к вашему сожалению - да – Artem L. Jan 19 '21 at 19:48
  • @ПавелЕриков этот код берет MediaControlCenter информацию о воспроизводимой композиции. Проверяет через несколько заданных правил и отправляет в textblock и .txt файл. Уточню в вопросе. Спасибо, что подсказали. – Artem L. Jan 19 '21 at 19:52
  • @ArtemL. там в ответах уже рассказали о копипасте. Самое главное тут, мне кажется, что большинство вещей (форматы, строки, некоторые проверки и т.д.) можно выполнить в XAML на стороне представления. Вам нужно разделить понятия поставищика данных и представления этих данных. Попробуйте прочитать о MVVM-шаблоне. – Артём Оконечников Jan 19 '21 at 19:54
  • @АртёмОконечников я первый раз использую WPF. Вы можете подсказать, что можно выполнить в XALM*? – Artem L. Jan 19 '21 at 20:26
  • 1
    Для знакомства с WPF и XAML, попробуйте почитать и разобрать этот пример. – aepot Jan 19 '21 at 20:28
  • @aepot извините, а почему пропал Ваш ответ? – Artem L. Jan 19 '21 at 22:25
  • Ну вы приняли другой ответ, я удалил как бесполезный. Если вам что-то еще из него надо, восстановил, простите. – aepot Jan 19 '21 at 22:26
  • @aepot Ваш ответ очень полезный лично для меня. Прямо по нему, сейчас изучаю аспекты некоторые аспекты программирования. Тот ответ, я отметил как лучший, так как он более оптимизирован. Вдруг, в будущем, кто-то будет искать как коротко оптимизировать и наткнётся на этот ответ. На данный момент, убрал отметку, т.к оба ответа, являются великолепными. Спасибо Вам, Вы мне действительно помогли разобраться! – Artem L. Jan 19 '21 at 22:30
  • @ArtemL. оптимизирован или код короче? Код короче - да, но фактически быстрее (хоть и незначительно) по производительности работать будет мой вариант. Но вам виднее, ок, если считаете полезным - оставлю ответ. А метку поставьте куда-нибудь, иначе вопрос будет считаться неотвеченным. – aepot Jan 19 '21 at 22:34

2 Answers2

4
  1. Добро пожаловать в Асинхронное программирование. Если вы используете .GetAwaiter().GetResult(), либо вы абсолютно точно уверены, что вы знаете, что делаете, либо что-то пошло не так, например вы не в курсе о существовании async/await. Нужно использовать await.
  2. Есть такая проверка на null - NULL-условный оператор ?.. Познакомьтесь с ним, очень сильно упрощает код в некоторых местах.
  3. У вас повторяется код, вы одно и то же условие перепроверяете по многу раз. Чтобы одно и то же перезаписать в текстовое поле. Вам по сути нужно построить строчку из кусочков, исходя из разных условий. Отлично! Для этого есть замечательный класс StringBuilder, к тому же он работает намного быстрее, чем интерполяция или конкатенация строк.
  4. if (b == true) можно заменить на if (b), а if (b == false) можно заменить на if (!b), потому что логическое выражение и так само по себе true или false и преобразовывать например true в true с помощью проверки на true - излишество.
  5. text != "" можно записать как text.Length > 0, ну потому что это технически работает быстрее. Так как числовые операции всегда быстрее строковых.

Вот моя попытка подчистить код согласно выше изложенному, но наверняка это еще можно улучшить.

public async void PrintCurrentlyPlaying(object sender, EventArgs e)
{
    // в async void методах обязательно нужно обрабатывать все возможные исключения, иначе вы их просто не увидите, а работать не будет
    try
    {
        var sessionManager = await GlobalSystemMediaTransportControlsSessionManager.RequestAsync();
        var currentSession = sessionManager?.GetCurrentSession();
        if (currentSession != null)
        {
            var mediaProperties = await currentSession.TryGetMediaPropertiesAsync();
            StringBuilder sb = new StringBuilder();
            if (unknown_artist.IsChecked && mediaProperties.Artist == "Неизвестный исполнитель")
            {
                if (!dash_instead_text.IsChecked)
                    sb.Append("Проигрывается: ");
                sb.Append(mediaProperties.Title);
            }
            else
            {
                if (dash_instead_text.IsChecked)
                {
                    sb.Append(mediaProperties.Title);
                    if (mediaProperties.Artist.Length > 0)
                        sb.Append(" - ").Append(mediaProperties.Artist);
                }
                else
                {
                    if (mediaProperties.Artist.Length > 0)
                    {
                        if (compocition_checkbox.IsChecked)
                        {
                            sb.Append("Проигрывается: ").Append(mediaProperties.Title);
                            if (author_checkbox.IsChecked)
                                sb.Append(", от автора: ").Append(mediaProperties.Artist);
                        }
                        else
                            sb.Append("Автор воспроизведения: ").Append(mediaProperties.Artist);
                    }
                    else
                        sb.Append("Проигрывается: ").Append(mediaProperties.Title); ;
                }
            }
            compocition_output.Text = sb.ToString();
        }
        else
            compocition_output.Text = "Упс... А музыка у нас закончилась!";
        if (output_file_checkbox.IsChecked)
        {
            file_save(null, null);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}
aepot
  • 49,560
  • В строке var currentSession = sessionManager?.GetCurrentSession(); зачем вы прописываете знак вопроса? .GetAwaiter().GetResult() брал из шаблона. Поэтому так и оставил. В чем проблема? Просто понять никак не могу. Почему await? – Artem L. Jan 19 '21 at 20:00
  • 1
    @ArtemL. Любопытно вы читаете что вам пишут, ибо в пункте 2 этого ответа сказано "зачем". А про async - можно и поискать. – EvgeniyZ Jan 19 '21 at 20:11
  • @ArtemL. про знак вопрос - пункт 2, про await - очень долгая история, связанная с понятиями Sync-over-Async и Deadlock. С чего начать знакомство с этой темой - используйте ссылку в п.1. Если не готовы разбираться, просто запомните, что GetAwaiter().GetResult() - это можно и нужно заменить на async/await. – aepot Jan 19 '21 at 20:17
  • @EvgeniyZ спросил по поводу знака вопроса потому, что вы в следующей же строке проверяете на null.. зачем тогда? – Artem L. Jan 19 '21 at 20:30
  • @ArtemL. Сколько у вас проверок на null и сколько у меня? Одну я заменил на ?.. – aepot Jan 19 '21 at 20:31
  • @aepot я к сожалению так и не понял, за какую проверку в моем коде, отвечает этот ?. Вы можете показать? Спасибо. – Artem L. Jan 19 '21 at 22:33
  • @ArtemL. за if (sessionManager != null). Почитайте документ по ссылке из второго пункта и все станет понятно. – aepot Jan 19 '21 at 22:35
  • @aepot "text != "" можно записать как text.Length > 0" может это всё же преждевременная оптимизация? Да и в первом варианте, я думаю сравнение двух ссылок из пула интернирования не очень дорогое – 4per Jan 22 '21 at 11:43
  • @4per то что компилятор затыкает дыры в знаниях разработчика оптимизациями не значит что не стоит знать решения для общего случая. :) В любом случае, это после оптимизации через Length будет работать либо так же, либо быстрее, хуже точно не будет. – aepot Jan 22 '21 at 11:48
  • @aepot зато семантика страдает – 4per Jan 22 '21 at 12:17
  • @4per я не знаю, что такое семантика. Но мне жаль, что она страдает. :) – aepot Jan 22 '21 at 12:22
3

Просто оставлю это здесь)

public async void PrintCurrentlyPlaying(object sender, EventArgs e)
{
    var currentSession = (await GlobalSystemMediaTransportControlsSessionManager.RequestAsync())?.GetCurrentSession(); // возращаем сессию
    if (currentSession != null) // если сессия не пустая, то
    {
        var mediaProperties = await currentSession.TryGetMediaPropertiesAsync(); // в mediaProperties мы отправляем название воспроизведения и имя автора
        var isUnknownArtist = mediaProperties.Artist is "" or "Неизвестный исполнитель";
    compocition_output.Text =
        (IsUnknownArtist: isUnknownArtist,
        UnknownArtistChecked: unknown_artist.IsChecked,
        DashInsteadText: dash_instead_text.IsChecked,
        IsAuthor: author_checkbox.IsChecked,
        IsCompocition: compocition_checkbox.IsChecked) switch
        {
            { UnknownArtistChecked: true, DashInsteadText: true, IsUnknownArtist: true } => $"{mediaProperties.Title}",
            { DashInsteadText: true, IsUnknownArtist: false } => $"{mediaProperties.Title} - {mediaProperties.Artist}",
            { DashInsteadText: true, IsUnknownArtist: true } => $"{mediaProperties.Title}",
            { IsUnknownArtist: false, IsAuthor: true, IsCompocition: true } => $"Проигрывается: {mediaProperties.Title}, от автора: {mediaProperties.Artist}",
            { IsUnknownArtist: false, IsAuthor: true, IsCompocition: false } => $"Автор воспроизведения: {mediaProperties.Artist}",
            _ => $"Проигрывается: {mediaProperties.Title}"
        };
}
else
    compocition_output.Text = "Упс... А музыка у нас закончилась!";

if (output_file_checkbox.IsChecked == true)
    file_save(null, null); // сохраняем название в .txt файл

}

Не проверял, да и уверен, что накосячил с некоторыми проверками, там уже если нужно будет, подправите под себя.

Весьма забавно было такое сжимать и сокращать. Вообще, вся ваша проблема в том, что... У вас много проблем, ибо у вас и UI используется как источник хранения данных и все смешано в одну кашу, попробуйте это разделить на отдельный, мало связанные друг с другом куски, тогда будет проще.

Из кода выше можно заметить, что некоторые проверки весьма странные и лишние, да и вообще не пойму зачем такая "динамика" в название, обычно это четко сформированный стандарт (аля: автор - трек), а остальное это "рюшечки" UI, может вам стоит пойти именно по этому пути?

Также из замечаний, почему метод PrintCurrentlyPlaying вдруг отвечает за сохранение? Print это вывести, а не сохранить.

Ну и про всякие async и прочее вам уже сказали другим ответом.


В моем примере используется последняя версия языка (C#9), можно без проблем опустить до C#8, заменив

var isUnknownArtist = mediaProperties.Artist is "" or "Неизвестный исполнитель";

на

var isUnknownArtist = string.IsNullOrWhiteSpace(mediaProperties.Artist) || mediaProperties.Artist == "Неизвестный исполнитель";

Ниже C#8 работать не будет, ибо все эти навороты с switch появились в нем (хотя кто знает, может умельцы сделали стороннюю библиотеку).

EvgeniyZ
  • 15,694
  • метод PrintCurrentlyPlaying был взят из шаблона и просто немного доработался моими кривыми руками. – Artem L. Jan 19 '21 at 19:56
  • @ArtemL. Шаблоны и инструкции зачастую делаются упрощенными, не нагруженными всякими паттернами и прочим. Например, если у вас WPF, то там используются привязки, а это значит, что вместо unknown_artist.IsChecked (обращения к UI) у вас должен быть класс с нужными свойствами, например класс "Информация трека", который содержит в себе свойства "Автор", "Название", "Тип трека", "Дата" и др. и уже с ним вы работаете. Также все ваши настройки, они должны быть в отдельном классе в виде простых свойств, а не в UI. Запомните простое правило - UI - это лишь взаимодействие с пользователем, не более. – EvgeniyZ Jan 19 '21 at 20:10
  • C# 9 же? Быть может стоит пометить, что этот код требует .NET 5? – aepot Jan 19 '21 at 20:26
  • @aepot Не, 8-го достаточно должно быть. – EvgeniyZ Jan 19 '21 at 20:27
  • or - это точно девятый. – aepot Jan 19 '21 at 20:29
  • 1
    @aepot Ай, по привычки уже пишу это. Добавил, что на что заменить, остальное точно 8-й. – EvgeniyZ Jan 19 '21 at 20:39