Функция оболочки Polly Try and Retry с универсальнымC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Функция оболочки Polly Try and Retry с универсальным

Сообщение Anonymous »

У меня есть функция-оболочка, которая принимает функцию, вызывающую вызов базы данных, возвращающую IEnumerable.
Этот тип T может быть любым из моих конкретный класс, который хранит возвращаемое целое число из базы данных.
Я заставил его работать, но в настоящее время он принимает только определенный IEnumerable. Как сделать так, чтобы я мог передавать любой IEnumerableлюбому из моих классов?
А также как обрабатывать результат в OnRetry? Поскольку он должен иметь доступ к параметру IEnumerable, который в каждом классе называется по-разному.

Код: Выделить всё

public static async ValueTask KeepTrying(Func func, int expectedInteger) where TResult : IEnumerable
{

var pipeline = new ResiliencePipelineBuilder()
.AddRetry( new RetryStrategyOptions(){

ShouldHandle = new PredicateBuilder().Handle()
.HandleResult(result => result.First().MyInteger != expectedInteger),
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(2)
})
.Build();

return await pipeline.ExecuteAsync(token => new ValueTask(func()));

}

Вызов этой оболочки:

Код: Выделить всё

var result = await KeepTrying(() => DB.MyFunction(), expectedInteger: 100);
Ответы на обновление 2

  • Без надлежащего контекст, я не могу сказать, когда генерируется NotFoundException. Но по обоснованному предположению, он выдается тогда, когда в противном случае функция базы данных вернула бы ноль. Но пустая и пустая коллекция — это не одно и то же.
Верно. Сначала я проверяю, пуста ли она:

Код: Выделить всё

if (result.Count == 0)
throw new NotFoundException("Some error");

return result;
Достаточно ли эта проверка для выявления подверженного ошибкам результата.First().MyInteger?
  • Я не уверен на 100 %, что под этим подразумевается. Не могли бы вы перефразировать это? (Что касается обработки других типов)
Конечно, то, что я сделал до сих пор, работает, но я хорошо это знаю может быть очень сомнительный дизайн.
Иногда мне хочется вернуть из базы данных не только целое число, но и логическое значение или строку.
И что я сделал я добавил новое свойство в IMyInteger (фактически переименовал его в IReturnedValueFromDatabase, поскольку это не только int).

Код: Выделить всё

public interface IReturnedValueFromDatabase
{
public int ReturnedInteger { get; set; } // was MyInteger
public bool ReturnedBool { get; set; }
public string ReturnedString { get; set; }
}
Теперь я добавил несколько вещей в KeepTrying():
Добавил новые параметры, допускающие значение NULL, поэтому в HandleResult я знаю, какой из них следует проверить:

Код: Выделить всё

public static async ValueTask KeepTrying(..., int? expectedNumber = null, bool? expectedBool = null, bool handleResult = true) where TResult : IReturnedValueFromDb
{
// skipping to .HandleResult()
.HandleResult(result => {

if (!handleResult)
// Sometimes I want to only handle Exception and not to check result, so added this check, but maybe there is better way?
return false;

if (expectedNumber != null)
// I am passing int so lets check int
return result.First().ReturnedInteger != expectedNumber;

if (expectedBool != null)
// I am passing bool so lets check bool
return result.First().ReturnedBool != expectedBool;

// all else fails, throw exception
throw new InvalidOperationException("Unable to determine result");
})
}

Надеюсь, я снова не слишком запутал вас. По сути, я возвращаю разные значения из БД, поэтому хочу сделать функцию как можно более универсальной, но при этом оставаться СУХОЙ. Я не знаю, ужасный ли это дизайн, и, возможно, мне следует создать разные функции для каждого типа или есть другой способ.
  • Что касается исключения, выдаваемого функцией KeepTrying()
Когда я запускаю его в тесте и KeepTrying ничего не вернет, тест не завершится неудачно, поэтому я предполагаю, что он не выдает исключение, но, вероятно, оно просто где-то теряется. Думаю, я могу использовать try/Exception в KeepTrying, как вы предложили, или в тесте, где я вызываю KeepTrying (чтобы я мог удалить следующий оператор Assert.That). Но сейчас это не так важно.
  • использование Execute вместо ExecuteAsync
Если это не проблема, я могу использовать Execute, как вы предлагаете. Мне еще многое предстоит узнать об этих вещах. Спасибо!
Обновление 3


Вы можете избежать создания исключения. Вы можете просто использовать .Any внутри HandleResult

Извините, это могло сбить с толку из-за того же результата именования — это выдержка из моей базы данных функция, в которой я выдаю исключение, если result.Count == 0, или возвращаю результат в противном случае.
Я создал dotnetfiddle с текущей версией
Поэтому я теперь тоже запутываюсь, не уверен, что вы имели в виду исключение внутри .HandleResult() - могу ли я удалить флаг bool? handleResult = true из KeepTrying() и внутри HandleResult вместо этого выполните:

Код: Выделить всё

if (!result.Any()) // In case I don't want to check result?
return false;
Думаю, было бы лучше, если бы вы просто переписали скрипку со своими предложениями, чтобы избежать дальнейшей путаницы.

с помощью селектора свойств

Конечно, я могу попробовать, по крайней мере сейчас это работает. Я буду продолжать корректировать и посмотреть.

Основываясь на этом описании, я предполагаю, что вы не ожидаете метода KeepTrying внутри своего теста. дождитесь его, и оно должно выдать исключение.

На самом деле я использую await (см. Тестовый класс в скрипте) - если Я удаляю await, получаю сообщение об ошибке Невозможно разрешить символ 'First' из следующей строки Assert.That(myNumber.First().ReturnedInteger), что странно, потому что я изменил KeepTrying() для синхронизации, но это может быть потому, что тест является асинхронным?
Странное поведение заключается в том, что, когда результат неверен, он правильно повторяет попытку, но не генерирует исключение, вот почему Я также использую Assert.That в следующей строке - если KeepTrying выдаст исключение, я мог бы удалить его.
Я получал бы исключение из HandleResult() только тогда, когда я передал бы его. аргументов имеет значение null, например ожидаемый номер = null. Есть некоторые странные варианты поведения, но я могу избежать их, если буду использовать функцию только так, как ожидалось - возможно, еще один вопрос:
Для функций БД, когда я не проверяю результаты и просто хочу убедиться, что что-то вернулось (т.е. NotFoundException не было создано), является ли мой флаг handleResult достаточно хорошим решением, чтобы игнорировать проверяемое решение?
В любом случае, если на данный момент это слишком запутанно, не беспокойтесь, вы уже мне помогло и заставило функцию работать! Спасибо большое за это.

Подробнее здесь: https://stackoverflow.com/questions/781 ... th-generic
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Функция оболочки Polly Try and Retry с универсальным
    Гость » » в форуме C#
    0 Ответы
    18 Просмотры
    Последнее сообщение Гость
  • Политика Polly Retry блокирует или ждет успеха
    Anonymous » » в форуме C#
    0 Ответы
    37 Просмотры
    Последнее сообщение Anonymous
  • C# Polly, Polly не работает, если функция завершится
    Anonymous » » в форуме C#
    0 Ответы
    20 Просмотры
    Последнее сообщение Anonymous
  • Java Reflection – получить универсальный тип с возможным универсальным или универсальным типом?
    Гость » » в форуме JAVA
    0 Ответы
    22 Просмотры
    Последнее сообщение Гость
  • WPF: В чем разница между try...finally и try..catch..finally в WPF, MVVM? [закрыто]
    Гость » » в форуме C#
    0 Ответы
    43 Просмотры
    Последнее сообщение Гость

Вернуться в «C#»