Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步任务<;IEnumerable>;有收益回报吗?_C#_Async Await - Fatal编程技术网

C# 异步任务<;IEnumerable>;有收益回报吗?

C# 异步任务<;IEnumerable>;有收益回报吗?,c#,async-await,C#,Async Await,下面的方法无法编译。替代品 public static async Task<IEnumerable<object[]>> GetRecordsAsync( this Transaction transaction, string commandText, params SqlParameter[] parameters) { // Get a SqlDataReader var reader = await transaction

下面的方法无法编译。替代品

public static async Task<IEnumerable<object[]>> GetRecordsAsync(
    this Transaction transaction,
    string commandText,
    params SqlParameter[] parameters)
{
    // Get a SqlDataReader
    var reader = await transaction.GetReaderAsync(commandText, parameters);
    var fieldCount = -1;
    // Begin iterating through records asynchronously
    while (await reader.ReadAsync()) // Note we don't loop until .ReadAsync returns a boolean
    {
        // Grab all the field values out
        if (fieldCount < 0)
            fieldCount = reader.FieldCount;
        var fields = new object[fieldCount];
        reader.GetValues(fields);
        // Yield return the field values from this record
        yield return fields;
    }
}
公共静态异步任务GetRecordsAsync(
本次交易,
字符串命令文本,
参数SqlParameter[]参数)
{
//获取SqlDataReader
var reader=await transaction.GetReaderAsync(commandText,参数);
变量fieldCount=-1;
//开始异步遍历记录
while(wait reader.ReadAsync())//注意,在.ReadAsync返回布尔值之前,我们不会循环
{
//抓取所有字段值
如果(字段计数<0)
fieldCount=reader.fieldCount;
变量字段=新对象[fieldCount];
reader.getValue(字段);
//Yield返回此记录中的字段值
产量回报场;
}
}
错误消息:

“TransactionExtensions.GetRecordsAsync(Transaction,string,params SqlParameter[])的主体不能是迭代器块,因为“Task>”不是迭代器接口类型

我看不到一种方法来适应一个类似的(但不同的)问题,因为我不知道循环会进行多少次


编辑:固定格式

根据@SLaks对问题的评论,这里有一个通用的替代方法:


我在没有第三方扩展的情况下解决了这个问题:

public async Task<IEnumerable<Item>> GetAllFromDb()
{
    OracleConnection connection = null;
    DbDataReader reader = null;
    try
    {
        connection = new OracleConnection(connectionString);
        var command = new OracleCommand(queryString, connection);
        connection.Open();

        reader = await command.ExecuteReaderAsync();

        return this.BuildEnumerable(connection, reader);
    }
    catch (Exception)
    {
        reader?.Dispose();
        connection?.Dispose();          
        throw;
    }
}

private IEnumerable<Item> BuildEnumerable(OracleConnection connection, DbDataReader reader)
{
    using (connection)
    using (reader)
    {
        while (reader.Read())
        {
            var item = new Item()
            {
                Prop = reader.GetString(0),
            };
            yield return item;
        }
    }
}
公共异步任务GetAllFromDb() { OracleConnection=null; DbDataReader=null; 尝试 { 连接=新的OracleConnection(connectionString); var命令=新的OracleCommand(查询字符串,连接); connection.Open(); reader=wait命令.ExecuteReaderAsync(); 返回此.BuildEnumerable(连接、读取器); } 捕获(例外) { 读卡器?.Dispose(); 连接?.Dispose(); 投掷; } } 私有IEnumerable BuildEnumerable(OracleConnection连接、DbDataReader) { 使用(连接) 使用(读卡器) { while(reader.Read()) { 变量项=新项() { Prop=reader.GetString(0), }; 收益回报项目; } } }
此示例适用于Oracle Data Reader,但相同的方法适用于任何与
收益返回相结合的异步操作

IEnumerable
本身不支持该操作。使用反应式扩展。您可以使用ObservableCollection监视正在添加的元素。创建并将其传递给GetRecordsAsync,它现在将只返回任务,并在准备好生成
字段后添加到任务中。现在我考虑一下,简单地将“on fields received”委托传递给该方法也是可能的。@IllidanS4我认为这可以归结为SLaks给出的注释。这两个都是好主意,但也带来了很多其他好处bear@MattThomas,也可以通过via查看一些其他想法。谢谢链接。我从中得到的最好的选择是Rx。对我来说,答案就像Rx(或者更一般地说,pub-sub)所做的一样,但在这个问题的核心,你称之为reader.Read(),即阻塞方法。它可以编译并运行,但我认为您并没有获得真正的异步好处;因此,如果正确执行此操作,将解锁线程。关于读取操作-我同意@Henk Holterman的观点,它是同步的。但是,如果您想使用标准C#、Linq、foreach等,这是最好的折衷方案。
/// <summary>
/// Asynchronously processes each record of the given reader using the given handler
/// </summary>
static async Task ProcessResultsAsync(this SqlDataReader reader, Action<object[]> fieldsHandler)
{
    // Set up async functions for the reader
    var shouldLoopAsync = (Func<Task<bool>>)reader.ReadAsync;
    var getAsync = new Func<SqlDataReader, Func<Task<object[]>>>(_reader =>
    {
        var fieldCount = -1;
        return () => Task.Run(() =>
        {
            Interlocked.CompareExchange(ref fieldCount, _reader.FieldCount, -1);
            var fields = new object[fieldCount];
            _reader.GetValues(fields);
            return fields;
        });
    })(reader);

    // Turn the async functions into an IObservable
    var observable = ToObservable(shouldLoopAsync, getAsync);

    // Process the fields as they become available
    var finished = new ManualResetEventSlim(); // This will be our signal for when the observable completes
    using (observable.Subscribe(
        onNext: fieldsHandler, // Invoke the handler for each set of fields
        onCompleted: finished.Set // Set the gate when the observable completes
    )) // Don't forget best practice of disposing IDisposables
        // Asynchronously wait for the gate to be set
        await Task.Run((Action)finished.Wait);
}
// Get a SqlDataReader
var reader = await transaction.GetReaderAsync(commandText, parameters);
// Do something with the records
await reader.ProcessResultsAsync(fields => { /* Code here to process each record */ });
public async Task<IEnumerable<Item>> GetAllFromDb()
{
    OracleConnection connection = null;
    DbDataReader reader = null;
    try
    {
        connection = new OracleConnection(connectionString);
        var command = new OracleCommand(queryString, connection);
        connection.Open();

        reader = await command.ExecuteReaderAsync();

        return this.BuildEnumerable(connection, reader);
    }
    catch (Exception)
    {
        reader?.Dispose();
        connection?.Dispose();          
        throw;
    }
}

private IEnumerable<Item> BuildEnumerable(OracleConnection connection, DbDataReader reader)
{
    using (connection)
    using (reader)
    {
        while (reader.Read())
        {
            var item = new Item()
            {
                Prop = reader.GetString(0),
            };
            yield return item;
        }
    }
}