Асинхронные методы не могут иметь параметры ref или out [duplicate]

Да, \ в строковых литералах Python обозначает начало escape-последовательности. На вашем пути у вас есть действительная двухсимвольная escape-последовательность \a, которая сжимается на символ one , который является ASCII Bell :

>>> '\a'
'\x07'
>>> len('\a')
1
>>> 'C:\meshes\as'
'C:\\meshes\x07s'
>>> print('C:\meshes\as')
C:\meshess

Другие общие escape-последовательности включают в себя \t (вкладка), \n (строка), \r (возврат каретки):

>>> list('C:\test')
['C', ':', '\t', 'e', 's', 't']
>>> list('C:\nest')
['C', ':', '\n', 'e', 's', 't']
>>> list('C:\rest')
['C', ':', '\r', 'e', 's', 't']

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

Существует множество способов борьбы с этим:

  1. Python будет не обрабатывать escape-последовательности в строковых литералах с префиксом r или R :
    >>> r'C:\meshes\as'
    'C:\\meshes\\as'
    >>> print(r'C:\meshes\as')
    C:\meshes\as
    
  2. Python в Windows также должен обрабатывать косые черты.
  3. используйте os.path.join ...
    >>> import os
    >>> os.path.join('C:', os.sep, 'meshes', 'as')
    'C:\\meshes\\as'
    
  4. ... или новый pathlib модуль
    >>> from pathlib import Path
    >>> Path('C:', '/', 'meshes', 'as')
    WindowsPath('C:/meshes/as')
    

95
задан Yuval Itzchakov 24 July 2015 в 16:07
поделиться

6 ответов

Вот код ответа @ dcastro, измененный для C # 7.0 с именованными кортежами и декодированием кортежей, который упрощает обозначение:

public async void Method1()
{
    // Version 1, named tuples:
    // just to show how it works
    /*
    var tuple = await GetDataTaskAsync();
    int op = tuple.paramOp;
    int result = tuple.paramResult;
    */

    // Version 2, tuple deconstruction:
    // much shorter, most elegant
    (int op, int result) = await GetDataTaskAsync();
}

public async Task<(int paramOp, int paramResult)> GetDataTaskAsync()
{
    //...
    return (1, 2);
}

Подробнее о новых именованных кортежах, литералах и фрагментах кортежей см. : https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/

163
ответ дан Jpsy 25 August 2018 в 07:19
поделиться

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

Обратите внимание, что ни один из этих методов не будет иметь какого-либо принудительного исполнения от компилятора, который out имеет , Т.е. компилятор не потребует установки значения для общего объекта или вызова переданного в делегате.

Вот пример реализации с использованием общего объекта для имитации ref и out для использования с методами async и другими различными сценариями, где ref и out недоступны:

class Ref<T>
{
    // Field rather than a property to support passing to functions
    // accepting `ref T` or `out T`.
    public T Value;
}

async Task OperationExampleAsync(Ref<int> successfulLoopsRef)
{
    var things = new[] { 0, 1, 2, };
    var i = 0;
    while (true)
    {
        // Fourth iteration will throw an exception, but we will still have
        // communicated data back to the caller via successfulLoopsRef.
        things[i] += i;
        successfulLoopsRef.Value++;
        i++;
    }
}

async Task UsageExample()
{
    var successCounterRef = new Ref<int>();
    // Note that it does not make sense to access successCounterRef
    // until OperationExampleAsync completes (either fails or succeeds)
    // because there’s no synchronization. Here, I think of passing
    // the variable as “temporarily giving ownership” of the referenced
    // object to OperationExampleAsync. Deciding on conventions is up to
    // you and belongs in documentation ^^.
    try
    {
        await OperationExampleAsync(successCounterRef);
    }
    finally
    {
        Console.WriteLine($"Had {successCounterRef.Value} successful loops.");
    }
}
8
ответ дан Community 25 August 2018 в 07:19
поделиться

C # 7 + Solution заключается в использовании неявного синтаксиса кортежа.

    private async Task<(bool IsSuccess, IActionResult Result)> TryLogin(OpenIdConnectRequest request)
    { 
        return (true, BadRequest(new OpenIdErrorResponse
        {
            Error = OpenIdConnectConstants.Errors.AccessDenied,
            ErrorDescription = "Access token provided is not valid."
        }));
    }

Результат возврата использует имена свойств, определенные сигнатурой метода. например:

var foo = await TryLogin(request);
if (foo.IsSuccess)
     return foo.Result;
3
ответ дан jv_ 25 August 2018 в 07:19
поделиться

Я думаю, что использование ValueTuples, как это, может работать. Сначала нужно добавить пакет ValueTuple NuGet, хотя:

public async void Method1()
{
    (int op, int result) tuple = await GetDataTaskAsync();
    int op = tuple.op;
    int result = tuple.result;
}

public async Task<(int op, int result)> GetDataTaskAsync()
{
    int x = 5;
    int y = 10;
    return (op: x, result: y):
}
1
ответ дан Paul Marangoni 25 August 2018 в 07:19
поделиться

Алекс сделал замечательную точку зрения на удобочитаемость. Эквивалентно, функция также является интерфейсом, достаточным для определения возвращаемого типа (типов), и вы также получаете значимые имена переменных.

delegate void OpDelegate(int op);
Task<bool> GetDataTaskAsync(OpDelegate callback)
{
    bool canGetData = true;
    if (canGetData) callback(5);
    return Task.FromResult(canGetData);
}

Абоненты предоставляют лямбду (или названную функцию), а intellisense помогает при копировании имя переменной из делегата.

int myOp;
bool result = await GetDataTaskAsync(op => myOp = op);

Этот конкретный подход похож на метод «Try», где myOp установлен, если результатом метода является true. В противном случае вам все равно myOp.

6
ответ дан Scott Turner 25 August 2018 в 07:19
поделиться

Вы не можете иметь параметры ref или out в методах async (как уже было отмечено).

Это кричит для некоторого моделирования в движущихся данных:

public class Data
{
    public int Op {get; set;}
    public int Result {get; set;}
}

public async void Method1()
{
    Data data = await GetDataTaskAsync();
    // use data.Op and data.Result from here on
}

public async Task<Data> GetDataTaskAsync()
{
    var returnValue = new Data();
    // Fill up returnValue
    return returnValue;
}

Вы получаете возможность повторно использовать свой код более легко, а также более читабельны, чем переменные или кортежи.

35
ответ дан superjos 25 August 2018 в 07:19
поделиться
Другие вопросы по тегам:

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