3

我正在学习将 Rx 扩展用于我正在开发的 Silverlight 4 应用程序。我创建了一个示例应用程序来确定该过程,但我无法让它返回任何东西。这是主要代码:

    private IObservable<Location> GetGPSCoordinates(string Address1)
    {
        var gsc = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService") as IGeocodeService;

        Location returnLocation = new Location();
        GeocodeResponse gcResp = new GeocodeResponse();

        GeocodeRequest gcr = new GeocodeRequest();
        gcr.Credentials = new Credentials();
        gcr.Credentials.ApplicationId = APP_ID2;
        gcr.Query = Address1;

        var myFunc = Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>(gsc.BeginGeocode, gsc.EndGeocode);
        gcResp = myFunc(gcr) as GeocodeResponse;

        if (gcResp.Results.Count > 0 && gcResp.Results[0].Locations.Count > 0)
        {
            returnLocation = gcResp.Results[0].Locations[0];
        }
        return returnLocation as IObservable<Location>;
    }

gcResp 返回为空。任何想法或建议将不胜感激。

4

3 回答 3

1

您订阅的可观察源是异步的,因此您无法在订阅后立即访问结果。您需要访问订阅中的结果。

更好的是,根本不订阅,只需编写响应:

private IObservable<Location> GetGPSCoordinates(string Address1)
{
    IGeocodeService gsc = 
        new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");

    Location returnLocation = new Location();
    GeocodeResponse gcResp  = new GeocodeResponse();

    GeocodeRequest gcr = new GeocodeRequest();
    gcr.Credentials = new Credentials();
    gcr.Credentials.ApplicationId = APP_ID2;
    gcr.Query = Address1;

    var factory = Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>(
        gsc.BeginGeocode, gsc.EndGeocode);

    return factory(gcr)
        .Where(response => response.Results.Count > 0 && 
                           response.Results[0].Locations.Count > 0)
        .Select(response => response.Results[0].Locations[0]);
}

如果只需要第一个有效值(地址的位置不太可能改变),那么在和.Take(1)之间添加一个。WhereSelect

编辑:如果您想专门处理未找到的地址,您可以返回结果并让消费者处理它,或者您可以返回异常并OnError在订阅时提供处理程序。如果你正在考虑做后者,你会使用SelectMany

return factory(gcr)
    .SelectMany(response => (response.Results.Count > 0 && 
        response.Results[0].Locations.Count > 0)
        ? Observable.Return(response.Results[0].Locations[0])
        : Observable.Throw<Location>(new AddressNotFoundException())
    );
于 2011-03-17T07:23:37.197 回答
0

如果您展开类型,myFunc您会看到它是Func<GeocodeRequest, IObservable<GeocodeResponse>>.

Func<GeocodeRequest, IObservable<GeocodeResponse>> myFunc =
    Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>
        (gsc.BeginGeocode, gsc.EndGeocode);

所以当你打电话时,myFunc(gcr)你有一个IObservable<GeocodeResponse>而不是一个GeocodeResponse。您的代码myFunc(gcr) as GeocodeResponse返回null,因为强制转换无效。

您需要做的是获取可观察对象的最后一个值,或者只是进行订阅。调用.Last()会阻塞。如果您致电,.Subscribe(...)您的回复将通过回拨线程。

试试这个:

gcResp = myFunc(gcr).Last();

让我知道你怎么去。

于 2011-03-17T01:11:35.223 回答
0

理查德(和其他人),

所以我有返回位置的代码,并且我有调用代码订阅。这是(希望)最后一期。当我调用 GetGPSCoordinates 时,下一条语句会立即执行,而无需等待订阅完成。这是按钮 OnClick 事件处理程序中的示例。

Location newLoc = new Location();

GetGPSCoordinates(this.Input.Text).ObserveOnDispatcher().Subscribe(x =>
            {
             if (x.Results.Count > 0 && x.Results[0].Locations.Count > 0)
                  {
                     newLoc = x.Results[0].Locations[0];
                     Output.Text = "Latitude: " + newLoc.Latitude.ToString() +
  ", Longtude: " + newLoc.Longitude.ToString();
                  }
             else
                  {
                    Output.Text = "Invalid address";
                  }
});
            Output.Text = " Outside of subscribe --- Latitude: " + newLoc.Latitude.ToString() +
  ", Longtude: " + newLoc.Longitude.ToString();

在订阅之外发生的 Output.Text 分配在订阅完成之前执行并显示零,然后订阅内的一个显示新的位置信息。

此过程的目的是获取位置信息,然后将其保存在数据库记录中,并且我在 Foreach 循环中按顺序处理多个地址。我选择 Rx Extensions 作为解决方案,以避免异步回调作为编码陷阱的问题。但似乎我已经将一个陷阱换成了另一个。

想法、意见、建议?

于 2011-03-17T19:27:18.187 回答