Как я могу выбросить ClassCastException из универсальной оболочки или во время компиляции

Это пример этого, но заметный ответ - вот что привело меня к этому.

var factory = new ConnectionFactory
{
    HostName = "MY_HOST_NAME",
    UserName = "USERNAME",
    Password = "PASSWORD",
    RequestedHeartbeat = 30
};

using (var connection = factory.CreateConnection())
{
    connection.ConnectionShutdown += (o, e) =>
    {                       
        //handle disconnect                            
    };

    using (var model = connection.CreateModel())
    {
        model.ExchangeDeclare(EXCHANGE_NAME, "topic");
        var queueName = model.QueueDeclare();

        model.QueueBind(queueName, EXCHANGE_NAME, "#"); 

        var consumer = new QueueingBasicConsumer(model);
        model.BasicConsume(queueName, true, consumer);

        while (!stop)
        {
            BasicDeliverEventArgs args;                       
            consumer.Queue.Dequeue(5000, out args);

            if (stop) return;

            if (args == null) continue;
            if (args.Body.Length == 0) continue;

            Task.Factory.StartNew(() =>
            {
                //Do work here on different thread then this one
            }, TaskCreationOptions.PreferFairness);
        }
    }
}

Несколько замечаний об этом.

Я использую # для темы. Это захватывает все. Обычно вы хотите ограничить тему.

Я устанавливаю переменную с именем «stop», чтобы определить, когда процесс должен завершиться. Вы заметите, что цикл работает вечно до тех пор, пока эта переменная не будет истинна.

Dequeue ждет 5 секунд, а затем выходит без получения данных, если нет нового сообщения. Это делается для того, чтобы мы прослушивали эту стоп-переменную и фактически уходили в какой-то момент. Измените значение по своему вкусу.

Когда приходит сообщение, я создаю код обработки в новом потоке. Текущий поток резервируется только для прослушивания сообщений rabbitmq, и если обработчик занимает слишком много времени для обработки, я не хочу, чтобы он замедлял другие сообщения. Это может потребоваться или не понадобиться в зависимости от вашей реализации. Однако будьте осторожны с написанием кода для обработки сообщений. Если вам понадобится минута, и вы получаете сообщения в суб-второй раз, у вас не хватит памяти или, по крайней мере, на серьезные проблемы с производительностью.

0
задан Dr Mido 4 March 2019 в 15:56
поделиться

1 ответ

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

class AWrapper<T extends A> {
    T a;
    Class<? super T> tClass; //new
    //Class<T> tClass; //or like this if exact match is needed

    AWrapper(T a, Class<? super T> tClass) { //edited
    //AWrapper(T a, Class<T> tClass) { //or like this if exact match is needed
        if (a.getClass().isInstance(tClass)) { //new
        //if (a.getClass().equals(tClass)){ //or like this if exact match is needed
            throw new ClassCastException("Object being wrapped is not of good type, the cause and solution is simply a programmer declared this generic type of an uncompatible type, this exception is designed to reduce runtime ClassCastExceptions by throwing them not at compiletime(impossible) but as soon as possible"); //new
        }
        this.a = a;
        this.tClass = tClass; //new
    }

    AWrapper(boolean b, Class<T> tClass) { //edited
        this((T) findObjectStupid(b), tClass); //edited
    }

    public T getA() {
        return a;
    }
}

<T extends A> T findObjectStupid(boolean b) {
    if (b) {
        return (T) new B1();
    } else {
        return (T) new B2();
    }
}

void main() {
    AWrapper<B1> rightWrapper = new AWrapper<>(true, B1.class); //edited
    AWrapper<B1> wrongWrapper = new AWrapper<>(false, B1.class);  //edited, now this throws exception just like we hoped

    B1 rightObject = rightWrapper.getA();
    B1 wrongObject = wrongWrapper.getA(); //never gets here
}

В приведенном выше коде класс сохраняется, так что позже объект T можно переназначить, но если присвоение выполняется только один раз в конструкторе, тогда строка Class<? super T> tClass; может быть полностью удалена. Удаляя эту строку, очевидно, все типы безопасности без снижения производительности (кроме фактического оператора if).

0
ответ дан Then Enok 4 March 2019 в 15:56
поделиться
Другие вопросы по тегам:

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