IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> 泛型和泛型方法扩展 -> 正文阅读

[开发工具]泛型和泛型方法扩展

泛型,顾名思义就是指一种抽象意义的数据类型,它满足一定的类型约束条件,比如必须要有无参的构造函数,或者必须继承某些接口,等等。如果说接口是对类成员的定义与声明的话,那么泛型是对类型声明方式的声明和约束,这些抽象的数据类型可以代表符合条件的多种类型的数据,这些类型有共同的处理逻辑。

比如对于系统标准的泛型List<T>,其中T代表任意的数据类型,List规定了可以同时存放多个T类型的数据,并且这些数据是有序排列的,List规定了T的访问方式,比如说List<T>,Add(T obj)代表向List添加一个孩子元素,后添加的元素序号大于前添加的元素,List实现了一套元素访问机制,可以对加入自己的T类型孩子进行增删改查,比如List<T>.RemoveAt(int i index)代表删掉加入的第i个孩子,List可以对队列中间任意一个位置插入一个元素等等。

List<K> List<T>,Join(List<U> b,Func<T,object> a,Func<U,obj> b,Func<T,U,K> c)

代表一种泛型方法,他实现了两个List<T> ,List<U>的关联方式,参数类型Func<T,object>代表一个以T类型数据作为输入,输出object类型的方法,系统将a和b这两个参数的取值逻辑委托给调用方,让调用方确定列表T和U返回的关联值,系统判断如果这两个值相等,就把T类型的数据行和U类型的数据行关联起来,最后一个参数c,也是一个委托,它将T数据和U数据作为数据,让调用方确定需要返回什么,也就是说K类型是调用方确定的,然后系统最终返回一个List<K>,调用方完全不需要知道List<T>和List<U>是如何关联的,只需要调用方输入必要的声明信息,系统自动处理。

结合这种特性,我们可以开发自定义的泛型。

下面举一个例子,说说使用泛型比不使用泛型的优势

假设我要通过一个地址去获取服务器数据,服务器返回一串结构化文本,我通过正则表达式去匹配我需要的数据然后返回一个List列表

常规的写法:

获取基金抬头数据

   public static IEnumerable<Fund> GetFund(string findstring = null)
    {
      string resultstr = Util.HttpCommon.HttpGet(@"http://fund.eastmoney.com/js/fundcode_search.js?v=" + DateTime.Now.ToString("yyyyMMddHHmmss"));
      //Regex regex = new Regex("var r = (?<Data>\\[\\[\"(?<Code>[0-9]{6})\",\".*?\",\"(?<Name>.*?)\",\"(?<Type>.*?)\".*?\\],{0,1})*\\]");
      Regex regex = new Regex("var r = (?<Data>\\[(\\[\"(?<Code>[0-9]{6})\"\\,\".*?\"\\,\"(?<Name>.*?)\"\\,\"(?<Type>.*?)\".*?\\][\\,]{0,1})+\\])");
      Match match = regex.Match(resultstr);
      //int matchSize = match.Groups["Code"].Captures.Count;

      IEnumerable<Fund> s = match.Groups["Code"].Captures.Cast<Capture>().Select((v, i) => new { value = v.Value, index = i }).Join(match.Groups["Name"].Captures.Cast<Capture>().Select((v, i) => new { value = v.Value, index = i }), a => a.index, b => b.index, (a, b) => new { Code = a.value, Name = b.value, a.index }).Join(match.Groups["Type"].Captures.Cast<Capture>().Select((v, i) => new { value = v.Value, index = i }), a => a.index, b => b.index, (a, b) => new Fund { Code = a.Code, Name = a.Name, Type = b.value }).Where(w => (findstring is null || (w.Code.Contains(findstring) || w.Name.Contains(findstring) || w.Type.Contains(findstring))) && !w.Name.EndsWith("(后端)"));
      return s;
    }

获取更新基金明细数据

public static void GetFundDetail(Fund fundCode)
    {
      if (fundCode.Detail == null)
      {
        if (fundCode.Type == "货币型" || fundCode.Type == "QDII")
        {
          return;
        }
        string resultstr = Util.HttpCommon.HttpGet($"https://fund.eastmoney.com/pingzhongdata/{fundCode.Code}.js?v={DateTime.Now.ToString("yyyyMMddHHmmss")}");

        if (resultstr.StartsWith("远程服务器返回错误"))
        {
          return;
        }

        Regex regex = new Regex("var Data_netWorthTrend = (?<Data>\\[(\\{\"x\"\\:(?<Date>[0-9]{13})\\,\"y\"\\:(?<Value>.*?)\\,.*?\\}[\\,]{0,1})+\\])");
        Match match = regex.Match(resultstr);
        fundCode.StartRecordTimeSpan = match.Groups["Date"].Captures.Cast<Capture>().First().Value;
        fundCode.LastRecordTimeSpan = match.Groups["Date"].Captures.Cast<Capture>().Last().Value;
        //fundCode.Detail = 
        fundCode.Detail = match.Groups["Date"].Captures.Cast<Capture>().Select((v, i) => new { index = i, value = Convert.ToSingle(v.Value) / 100000 }).Join(match.Groups["Value"].Captures.Cast<Capture>().Select((v, i) => new { index = i, value = Convert.ToDouble(v.Value) }), a => a.index, b => b.index, (a, b) => new Point { X = a.value, Y = b.value });
      }
      //DataService.UpdateFundDetail(fundCode);
    }

也就是只要想从网上新的一种数据,就需要重新创建一个方法

但是访问网络数据具有共同的逻辑

0.判断输入的合法性,调用网络接口的前提条件

1.根据输入的url发送一个HTTP Get请求,接收string结果

2.处理返回异常

3.通过正则解析结果,

4.将结果拼接成List列表返回

通过泛型可以只声明一个方法,向调用方暴露必要的输入信息,以及需要的返回类型数据

泛型实现

 /// <summary>
  /// 可数据服务的,使用泛型获取数据
  /// </summary>
  public static class DataServiceable
  {
    public static IEnumerable<T> GetData<T>(this DataService S, string url, string regexString, Func<T, string, string, bool> CallBackSetting) where T : new()
    {
      Regex regex = new Regex("\\(\\?\\<(?<Key>.*?)\\>");

      MatchCollection matchs = regex.Matches(regexString);

      List<string> keys = matchs.Cast<Match>().Select(s => s.Groups["Key"].Value).ToList();

      regex = new Regex(regexString);
      string resultstr = Util.HttpCommon.HttpGet(url);

      if (resultstr.StartsWith("远程服务器返回错误"))
      {
        return null;
      }

      Match match = regex.Match(resultstr);

      List<T> a = new List<T>();
      T t;
      foreach (string item in keys)
      {
        for (int i = 0; i < match.Groups[item].Captures.Count; i++)
        {
          if (a.Count > i)
          {
            t = a[i];
            CallBackSetting(t, item, match.Groups[item].Captures[i].Value);
          }
          else
          {
            t = new T();
            if (CallBackSetting(t, item, match.Groups[item].Captures[i].Value))
            {
              a.Add(t);
            }
          }

        }

      }
      return a;
    }
  }

定义了一个扩展方法,向DataService的实例添加一个GetData方法,其中GetData<T>让用户确定T是什么类型,系统返回List<T>

public static IEnumerable<T> GetData<T>(this DataService S, string url, 
string regexString, 
Func<T, string, string, bool> CallBackSetting) where T : new()
{...}

系统向调用方暴露需要输入的web地址,符合格式的正则字符串,以及如何将正则字符串中的标签和输出表字段关联起来的赋值逻辑,最后一个where T : new()?表示泛型必须要有一个无参的构造函数,这时系统就可以在内部直接创建一个泛型T的实例

t = new T();

调用委托调用方实现的方法

CallBackSetting(t, item, match.Groups[item].Captures[i].Value)

让调用方对泛型T数实例赋值

最终将赋值好的t添加到泛型List<T>的实例

List<T> a = new List<T>();
T t;

。。。
t = new T();
if (CallBackSetting(t, item, match.Groups[item].Captures[i].Value))
{
      a.Add(t);
}
。。。

return a;

调用泛型方法

DataService dataService = new DataService();
List<Fund> funds =dataService.GetData<Fund>(
        @"http://fund.eastmoney.com/js/fundcode_search.js?v=" + DateTime.Now.ToString("yyyyMMddHHmmss"), "var r = (?<Data>\\[(\\[\"(?<Code>[0-9]{6})\"\\,\".*?\"\\,\"(?<Name>.*?)\"\\,\"(?<Type>.*?)\".*?\\][\\,]{0,1})+\\])",
        (a, capture, u) => {
          switch (capture)
          {
            case "Code":
              a.Code = u;
              break;
            case "Type":
              a.Type = u;
              break;
            case "Name":
              a.Name = u;
              break;
            default:
              return false;
          }
          return true;
        }).Where(w => (findstring is null || (w.Code.Contains(findstring) || w.Name.Contains(findstring) || w.Type.Contains(findstring))) && !w.Name.EndsWith("(后端)"));

直接返回一个LIst<Fund>数据集

如果要以相同的方式获取其他的网络数据

List<Point> points = dataService.GetData<Point>(
        $"https://fund.eastmoney.com/pingzhongdata/{fundCode.Code}.js?v={DateTime.Now.ToString("yyyyMMddHHmmss")}", "var Data_netWorthTrend = (?<Data>\\[(\\{\"x\"\\:(?<Date>[0-9]{13})\\,\"y\"\\:(?<Value>.*?)\\,.*?\\}[\\,]{0,1})+\\])",
        (a, capture, u) =>
        {
          switch (capture)
          {
            case "Date":
              a.X = Convert.ToSingle(u) / 100000;
              break;
            case "Value":
              a.Y = Convert.ToDouble(u);
              break;
            default:
              return false;
          }
          return true;
        });

委托方法通过Lameda表达式实现,系统将正则匹配的结果和正则标签作为传入参数,让调用方如何确定将该标签的值传给实例元素的哪个字端,调用方返回一个bool类型数据,告诉系统是否有赋值操作,系统根据这个返回值确定是否需要将让调用方更新后的实例添加到List列表中。

系统直接返回一个点集List<Point>

调用方完全不需要关心系统是如何将通过地址去访问网络数据,如何处理异常,如何处理正则匹配,如何构造List和添加元素,只需要调用方将需要的信息声明出来,系统就知道如何处理。

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 23:24:56  更:2022-04-06 23:25:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:51:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码