Присвойте результат переданной функции объекту с типом переменной C# - PullRequest
0 голосов
/ 16 июня 2020

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

List<APIEntityProject> projectList = null;

private bool SetProjectList(){
    const maxRetries = 3;
    const RetryPause = 3000;
    int retries = 0;
    do
    {
        try
        {
            projectList = ProjApi.GetProject(activeWorkspace.WorkspaceCode);
        }
        catch (ApiException e)
        {
            if (e.ErrorCode == 401) // Unauthorized error (e.g. user doesn't have access to this Workspace
            {
                Log.Warning("Unauthorized error while fetching projects from Workspace, try {retries}",retries);
                retries++;
                System.Threading.Thread.Sleep(RetryPause * retries);//Waits 3 and then 6 seconds before retrying.
            }
            else throw;
        }
    } while (projectList == null || retries < maxRetries);
    if (retries == maxRetries)
    {
        Log.Error("An error has occured while trying to retrieve affected Projects, skipped document");
        errorCount++;
        return false;
    }
    return true;
}

Но, к сожалению, мне нужно воспроизводить этот Logi c так часто, что я хотел бы использовать его в функции, например RetryNTimes (аналогично Это решение

List<APIEntityProject> projectList = null;
List<APIEntityWBS> WBSList = null;
List<APIEntitySopeItem> SIList = null;
List<APIEntityScopeAsignment> SAList = null;
List<APIEntityActivity> ActList = null;
...

RetryNTimes(projectList,ProjApi.GetProject(activeWorkspace.WorkspaceCode),3,3000,"ProjectList");
RetryNTimes(WBSList, WBSApi.GetAllWBS(activeProject.ProjectID),3,3000,"WBSList");
RetryNTimes(SIList, SIApi.GetAllScopeItems(activeProject.ProjectID),3,3000,"ScopeItemsList");
RetryNTimes(SAList, SAApi.GetAllScopeAssignments(activeProject.ProjectID),3,3000,"ScopeAssignmentsList");
RetryNTimes(ActList, ActApi.GetAllActivities(activeProject.ProjectID),3,3000,"ActivityList");
...

private bool RetryNTimes(T object, Func<T> func, int times, int WaitInterval, string etext){
    do
    {
        try
        {
            object = func();
        }
        catch (ApiException e)
        {
            if (e.ErrorCode == 401)
            {
                retries++;
                Log.Warning("Unauthorized error while fetching {APIErrorSubject}, try {retries}",eText,retries);
                System.Threading.Thread.Sleep(RetryPause * retries);//Waits 3 and then 6 seconds before retrying.
            }
            else throw;
        }
    } while (object == null || retries < maxRetries);
    if (retries == maxRetries)
    {
        Log.Error("An error has occured while trying to retrieve {APIErrorSubject}, skipped document",eText);
        errorCount++;
        return false;
    }
    return true;
}

Я также прочитал typedef и указатели функций , но я не уверен, можно ли это делать с типами переменных. Есть идеи?

Ответы [ 2 ]

1 голос
/ 16 июня 2020

Эта статья относится к C языку. В C# вы можете использовать делегатов. Вот ссылка для начала.

0 голосов
/ 17 июня 2020

Основываясь на идее asawyer и просмотрев некоторые другие примеры делегатов Мне удалось заставить это работать.

static T2 TryNTimes<T1,T2>(Func<T1,T2> func,T1 obj, int times, int WaitInterval)
{
    while (times > 0)
    {
        try
        {
            T2 result = func.Invoke(obj);
            return result;
        }
        catch (Exception e)
        {
            if (--times <= 0)
                throw;
            System.Threading.Thread.Sleep(WaitInterval * times);
        }

    }
    return default;
}

Теперь мне нужно всего 2 шага в моя основная функция

activeWorkspace = TryNTimes(WrkApi.WorkspaceCodeWorkspaceCodeFindByName17, ServiceSettings.sqlConnection.Workspace, 3, 3000)[0];
ProjectList = TryNTimes(WrkApi.GetProjectsByWorkspaceCode, activeWorkspace.code, 3, 3000);

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

...