Ошибка: изменить цвет в гистограмме с накоплением ggplot2

Проблема заключается в том, что вы не реализуете перегрузку ExecuteWithLogging, которая решается специально для Func>. Помните, что лямбда-выражения могут быть преобразованы в любой совместимый делегат, поэтому ваша асинхронная лямбда успешно присваивается вашему текущему методу ExecuteWithLogging.

Прежде чем вы прочитаете остальную часть просьбы о ответе, посмотрите на после статьи , это очень помогло мне, когда я столкнулся с той же проблемой, с которой вы сейчас сталкиваетесь. Я почти уверен, что после прочтения этой статьи вы поймете, что здесь происходит, но для полноты здесь у вас есть образцы, которые сделают вещи более ясными. Я изменил ваши методы следующим образом:

public static async void SearchByPersonnummerAsync(string personnummer)
{
    var aaa = await ExcecuteWithLogging(async () =>
    {
        Console.WriteLine("Executing function");
        var res = await Task.Run(() =>
        {
            Thread.Sleep(100);
            Console.WriteLine("Before crashing");
            throw new Exception();
            return 1;
        });

        Console.WriteLine("Finishing execution");
        return res;
    });

}

private static T ExcecuteWithLogging(Func function)
{
    try
    {
        Console.WriteLine("Before calling function");
        function();
        Console.WriteLine("After calling function");
    }
    catch (Exception ex)
    {
        var message = ex.Message;
        Console.WriteLine(message);
    }

    Console.WriteLine("Returning..");
    return default(T);
}

Это именно то, где вы сейчас находитесь, я добавил только некоторый код ведения консоли, какой результат?

Как вы можете видеть, ExecutingWithLogging возвращается, когда делегат async даже не разбился!

Давайте добавим перегрузку, которая принимает Func>

private static async Task ExcecuteWithLogging(Func> function)
{
    T result;
    try
    {
        Console.WriteLine("Before calling function");
        result =  await function();
        Console.WriteLine("After calling function");

    }
    catch (Exception ex)
    {
        var message = ex.Message;
        Console.WriteLine(message);
        return default(T);

    }

    Console.WriteLine("Returning..");
    return result;
}

Компилятор теперь выберет это из статьи, упомянутой выше:

Компилятор предпочитает вызов метода, ожидающий делегата, который возвращает задачу. Это хорошо, потому что это тот, который вы предпочитаете использовать. Компилятор приходит к такому выводу, используя правила вывода типа о возвращаемом значении анонимных делегатов. Предполагаемый тип возвращаемого значения любой асинхронной анонимной функции считается заданием. Зная, что анонимная функция, представленная лямбдой, возвращает задачу, перегрузка Task.Run (), которая имеет аргумент Func, является лучшим совпадением.

Теперь вывод:

И вы получите доступ к выходу. Итак, что такое мораль? Опять же, я цитирую указанную статью:

Во-первых, избегайте использования async lambdas в качестве аргументов методам, ожидающим действия, и не предоставляйте перегрузку, ожидающую Func. Если вы это сделаете, вы создадите асинхронную lambda. Компилятор с радостью предположит, что это то, что вы хотите.

Во-вторых, если вы создаете методы, принимающие делегаты в качестве аргументов, подумайте, могут ли программисты использовать async лямбда в качестве этого аргумента. Если это так, создайте перегрузку, которая использует Func в качестве аргумента в дополнение к Action. В качестве следствия создайте перегрузку, которая принимает Func> в дополнение к Task для аргументов, которые возвращают значение.

EDIT. Как @Servy указывает на комментарии, если вы используете только оригинальную версию ExecuteWithLogging T на самом деле является Task ... но единственный способ, который я могу ожидать в ожидании без перегрузки:

private static async Task ExcecuteWithLogging(Func function)
{
    try
    {

        var result =  function();
        if (result is Task t)
        {
            return await t;
        }

        return result;
    }
    catch (Exception ex)
    {
        var message = ex.Message;
        Console.WriteLine(message);
    }

    Console.WriteLine("Returning..");
    return default(T);
}

Но, кроме того, что он уродливый ИМХО, он всегда терпит неудачу, поскольку вызов function() выполняется синхронно и к тому моменту, когда вы хотите дождаться, что задача уже завершена или сработала. Но худшая часть этого подхода заключается в том, что он даже не компилируется, компилятор жалуется на: Не может неявно преобразовывать тип void в T

1
задан Claudiu Papasteri 19 January 2019 в 15:04
поделиться

1 ответ

Чтобы перейти к формату оси Y в процентах, используйте пакет scales. Я дал ответ на то же самое здесь: Столпчатый столбец с процентами в R ggplot2 для категориальных переменных с нуля

library(tidyverse)
library(scales)
 IC %>% 
  mutate(morning=as.factor(morning),number=as.numeric(number)) %>% 
  ggplot(aes(station,number,fill=morning))+geom_bar(stat="identity",position = "fill")+
 scale_y_continuous(labels=scales::percent_format(),breaks=scales::pretty_breaks(n=10))+
  scale_fill_manual(values=c('#999999','#E69F00'))
0
ответ дан NelsonGon 19 January 2019 в 15:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: