Это пример этого, но заметный ответ - вот что привело меня к этому.
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, и если обработчик занимает слишком много времени для обработки, я не хочу, чтобы он замедлял другие сообщения. Это может потребоваться или не понадобиться в зависимости от вашей реализации. Однако будьте осторожны с написанием кода для обработки сообщений. Если вам понадобится минута, и вы получаете сообщения в суб-второй раз, у вас не хватит памяти или, по крайней мере, на серьезные проблемы с производительностью.
Существует только один способ стереть универсальную оболочку, создать поле, в котором точно указано, какой тип должен быть внутри, очевидно, это подразумевает небольшое снижение производительности, но гарантирует безопасность типов. Стоит ли оно того? Вероятно, нет.
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).