在VB.NET中延迟执行?

时间:2011-01-26 03:21:17

标签: vb.net deferred-execution

Private Sub LoadData(Of T)(ByVal query As ObjectQuery(Of T), 
    ByRef result As IEnumerable(Of T))
  If Connection.State = ConnectionState.Open Then
    result = query.ToArray
  Else
    AddHandler Connection.StateChange,
      Sub(sender As Object, e As StateChangeEventArgs)
        LoadData(query, result)
      End Sub
  End If
End Sub

在上面的代码中,我试图在连接不可用时递归LoadData函数,我想将加载推迟到可用时。

问题是上面的代码导致了编译器错误,因为a ByRef param cannot be used in lambda expressions

如何以正确的方式做到这一点?

2 个答案:

答案 0 :(得分:3)

你不能在lambda中使用ByRef参数,因为它可能指向堆栈上的一个位置,一旦lambda execue就不再存在。您所要做的就是使用更“永久”的存储位置。您可以传入一个属性为IEnumerable(Of T)的对象,您可以设置该对象以分配结果。

一个可能更好的选择是传入一个接受结果的委托(Action<IEnumerable<T>>)并执行调用者对结果所需的任何操作。这是C#中的一个例子:

void LoadData<T>(ObjectQuery<T> query, Action<IEnumerable<T>> action)
{
    if (Connection.State == ConnectionState.Open)
        action(query.ToArray());
    else
    {
        // create a lambda to handle the next state change
        StateChangeEventHandler lambda = null;
        lambda = (sender, e) =>
        {
            // only perform our action on transition to Open state
            if (Connection.State == ConnectionState.Open)
            {
                // unsubscribe when we're done
                Connection.StateChange -= lambda;
                action(query.ToArray());
            }
        }
        // subscribe to connection state changes
        Connection.StateChange += lambda;
    }
}

你会像这样调用LoadData

LoadData(query, results => listBox.DataSource = results);

请注意我的实施细微差别。例如,它不会在事件处理程序中调用自身,因为如果使用Open以外的状态调用处理程序,则会导致它重新订阅事件。一旦连接打开,它也会取消订阅事件。我不确定这会如何转化为VB,但在C#中这是一个3步骤的过程。首先,您必须声明一个变量来保存lambda并将其值设置为null。然后你创建lambda,它现在可以引用自己取消订阅。最后,您可以使用lambda订阅该事件。

答案 1 :(得分:0)

你遇到的问题是你的调用线程不知道变量是否已被LoadData()调用填充

在这种情况下,您需要执行以下操作:

  • 阻止执行直到加载完成
  • 加载完成时提升事件
  • 在装载程序上设置公开可见字段以指示装入状态

一个(可能的)妥协是返回自定义对象而不是IEnumerable

自定义对象可以立即尝试加载数据并继续重试直到成功。如果在发生加载之前读取自定义对象的结果集,则阻塞该线程直到加载完成,否则返回结果集

在这种情况下,如果负载发生和正在使用的数据之间存在延迟,您将获益 - 您的程序可以继续,直到需要数据。这是否有用完全取决于你使用它的目的。

有关阻止执行的更多信息: 这取决于你如何意识到连接已经恢复,但是有点像:

Public Sub LoadData(Of T)(ByVal query As ObjectQuery(Of T), ByRef result As IEnumerable(Of T))
  While Not Connection.State = ConnectionState.Open
    Threading.Thread.Sleep(100) 'Pick a decent value for this delay based on how likely it is the connection will be available quickly
  End While
  result = 'Use the connection to get your data
End Sub

你是否有任何理由将此作为带有ByRef参数的子而不是函数?你只是“返回”一个物体,所以我不太看到它的好处。并不是说它会在功能上产生巨大的差异,但它会更具可读性......

相关问题