none
遇到一个重大的!令人疑惑的!问题!报错:Value does not fall within the expected range.(详) RRS feed

  • 问题

  • 问题较难说明,容我慢慢道来:

    我的程序:需要从网络获取 JSON 数据,然后将其解析并呈现到界面,使用了 MvvmLight 、Json.Net。

    我的方案设计:因为有多个数据源(JSON),而且处理它们有大部分的相同逻辑,为此,我设计了一个 IDataService 接口 和 DataServiceBase 抽象类,而对于具体的 DataService 类,我现在只写了 2 个(但才 2 个就出奇葩问题了╮(╯-╰)╭)

    IDataService 接口:

        /// <summary>
        /// 表示数据服务的接口。
        /// </summary>
        /// <typeparam name="TData">表示数据的类型参数。</typeparam>
        public interface IDataService<TData>
        {
            /// <summary>
            /// 获取 <see cref="TData"/> 数据对象。
            /// </summary>
            /// <param name="id">表示数据的 ID。</param>
            /// <returns>返回一个 <see cref="TData"/> 对象。</returns>
            Task<TData> GetDataAsync(string id = null);
            /// <summary>
            /// 保存 <see cref="TData"/> 数据对象。
            /// </summary>
            /// <param name="id">表示数据的 ID。</param>
            /// <returns></returns>
            Task SaveDataAsync(string id = null);
        }

    DataServiceBase 抽象类:

    /// <summary> /// 表示数据服务的基类。 /// </summary> /// <typeparam name="TData">表示数据的类型参数。</typeparam> public abstract class DataServiceBase<TData> : IDataService<TData> { /// <summary> /// 获取访问数据源的 API。 /// </summary> protected abstract string Api { get; } /// <summary> /// 获取或设置数据源的 JSON 字符串。 /// </summary> protected virtual string JsonString { get; set; } /// 略。 /// <summary> /// 获取数据在本地的存储路径。 /// </summary> protected virtual async Task<string> GetFolderPathAsync() { // 略。 } /// <summary> /// 获取 <see cref="TData"/> 对象。 /// </summary> public TData Data { get; private set; } /// <summary> /// 获取 <see cref="TData"/> 对象。 /// </summary> /// <param name="id">表示数据的 ID。</param> /// <returns>返回一个 <see cref="TData"/> 对象。</returns> public virtual async Task<TData> GetDataAsync(string id = null) { // 优先从 Web 获取 “最新数据”。 await this.GetJsonStringFromWebAsync(); // 未成功获取数据则从 本地 获取 “缓存数据”。 if (String.IsNullOrWhiteSpace(this.JsonString)) { await this.GetJsonStringFromLocalAsync(); // 仍未成功获取数据则返回 “缺省值”。 if (String.IsNullOrWhiteSpace(this.JsonString)) { return default(TData); } }

    this.Data = await Task.Factory.StartNew(() => JsonConvert.DeserializeObject<TData>(this.JsonString)); return this.Data; } /// <summary> /// 保存 <see cref="TData"/> 对象。 /// </summary> /// <param name="id">表示数据的 ID。</param> /// <returns></returns> public virtual async Task SaveDataAsync(string id = null) { // 略。}

    /// <summary> /// 从 Web 获取 JSON 字符串。 /// </summary> /// <param name="id">代表 JSON 字符串的 ID。</param> /// <returns></returns> protected virtual async Task GetJsonStringFromWebAsync(string id = null) { try { HttpClient httpClient = new HttpClient(); this.JsonString = await httpClient.GetStringAsync(String.Format(this.Api, id)); } catch (HttpRequestException) { // 不需要做任何事。 } } }

    DataServiceA 具体服务类:

        /// <summary>
        /// 表示 <see cref="DataServiceA"/> 的数据源服务。
        /// </summary>
        public class DataServiceASource : DataServiceBase<DataServiceA>
        {
            /// <summary>
            /// 获取访问 <see cref="DataServiceA"/> 数据源的 API。
            /// </summary>
            protected override string Api { get; } = "略";
        }
    

    DataServiceB 具体服务类(与 DataServiceA 几乎一模一样):

        /// <summary>
        /// 表示 <see cref="DataServiceB"/> 的数据源服务。
        /// </summary>
        public class DataServiceBSource : DataServiceBase<DataServiceB>
        {
            /// <summary>
            /// 获取访问 <see cref="DataServiceB"/> 数据源的 API。
            /// </summary>
            protected override string Api { get; } = "略";
        }
    

    出错过程:View 现在暂时也只有 2 个,分别为 PageA、PageB,另外还有 2 个 ViewModel,分别为 PageAViewModel、PageBViewModel,对应关系看 A、B 名称就知道了!

    PageA.xaml.csPageB.xaml.cs 类似):

        /// <summary>
        /// 可用于自身或导航至 Frame 内部的空白页。
        /// </summary>
        public sealed partial class PageA : Page
        {
            /// <summary>
            /// 获取当前 View 的 ViewModel.
            /// </summary>
            public PageAViewModel Vm
            {
                get
                {
                    return (PageAViewModel)DataContext;
                }
            }
    
            public PageA()
            {
                this.InitializeComponent();
            }
    
            protected override async void OnNavigatedTo(NavigationEventArgs e)
            {
                await Vm.GetAAsync(); ★请注意下这里 ★请注意下这里 ★请注意下这里
    
                await Vm.SaveAAsync();  
            }
        }
    

    PageAViewModelPageBViewModel 类似)

        public class PageAViewModel : ViewModelBase
        {
            private DataServiceA _dataServiceA;
    
            private A _a;
            public A A
            {
                get
                {
                    return this._a;
                }
                set
                {
                    Set(ref this._a, value);
                }
            }
    
            public PageAViewModel()
            {
                this._dataServiceA= new DataServiceA();
            }
    
            public async Task GetAAsync()
            {
                this.A= await this._dataServiceA.GetDataAsync();
            }
    
            public async Task SaveAAsync()
            {
                await this._dataServiceA.SaveDataAsync();
            }
        }

    出错过程(续):我发现,当我还没写 PageB.xaml.cs 的 (★) 处时(也就是说只写好了 A 有关的部分),A 数据可以正常的获取并呈现在界面上!但当我也把 B 相关部分写好后就出现:

    Value does not fall within the expected range.

     错误了!

    我的排错过程:我试着注释掉 A 的 (★) 处,发现问题依旧,所以,我猜测是 B 的 (★)处的问题。但令人感到更疑惑了==,毕竟 A、B 部分都几乎是一模一样的!

    2015年11月17日 4:11

答案

  • 没有重复的,PageAPageB 页面差别较大,我是独立写的。最开始是硬编码数据,现在只是改成从网络获取数据了。

    更诡异的是调试的时候,(★)处发生了异常,但我进入(★)内部逐行调试时发现一切都正常,JSON 数据获取成功,也解析成功。

    ======================↓更新↓========================

    握草!原来是 数据绑定的时候少了一级属性!!!这。。。


    2015年11月17日 6:52

全部回复

  • 你再仔细检查下XAML code 是否因为你的PageB 大部分复制于PageA XAML里面有了重复的名字,声明,仔细检查XAML。 应该不是C#这里的问题。

    Bob Bao

    Do you still use the same Windows 8 LockScreen always? Download Chameleon Win8 App quickly, that changes your LockScreen constantly.
    你是否还在看着一成不变的Windows 8锁屏而烦恼,赶紧下载这个 百变锁屏 应用,让你的锁屏不断地变化起来。

    2015年11月17日 5:57
  • 没有重复的,PageAPageB 页面差别较大,我是独立写的。最开始是硬编码数据,现在只是改成从网络获取数据了。

    更诡异的是调试的时候,(★)处发生了异常,但我进入(★)内部逐行调试时发现一切都正常,JSON 数据获取成功,也解析成功。

    ======================↓更新↓========================

    握草!原来是 数据绑定的时候少了一级属性!!!这。。。


    2015年11月17日 6:52