2
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 函数,我想将加载推迟到它可用时。

问题是上面的代码会导致编译器错误,因为参数ByRef不能在 lambda 表达式中使用

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

4

2 回答 2

3

您不能ByRef在 lambda 中使用参数,因为它可能指向堆栈上的位置,一旦 lambda 执行,该位置就不再存在。您所要做的就是使用更“永久”的存储位置。您可以传入一个具有您可以设置的属性的对象,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 订阅事件。

于 2011-01-26T03:41:43.817 回答
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 参数的子程序而不是函数?你只是“返回”一个对象,所以我看不到好处。并不是说它在功能上会有很大的不同,但它会更具可读性......

于 2011-01-26T03:43:12.753 回答