ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 2241|回复: 1

[分享] 封装,多态,依赖注入等

[复制链接]

TA的精华主题

TA的得分主题

发表于 2016-3-3 19:03 | 显示全部楼层 |阅读模式
前言
        本帖是接上一个贴的基础贴,理论上来说也是一个基础知识,但会加上更多的实际项目来说明.涉及的知识点比较多.因此建议有一定基础的才去了解,至少要学会我之前的基础贴所说的内容.
涉及点如下:
1.      封装(重点)
2.      分层(简单)
3.      多态
4.      依赖注入
5.      面向对象分析,设计.(少量)
6.      设计模式(少量)

为什么学习vsto要知道这么多东西呢?不就是跟vba一样,调用,调用,再调用吗?恐怕是很多人的想法.在我看来,vba板块是把vba作为脚本语言来编写应用,不是说不妥,而是当你看到一次次重复的代码出现在不同的项目,相同功能的东西要重复调试,这样只是把手动重复操作变成手动重复编码而已.从vba转到.net上的同学很多是把C#或vb.net当做脚本来使用,这样就不能发挥强类型和静态语言的优势.

我不排除有些人在某些阶段是很喜欢写代码,但我觉得很多人学到一定程度会跟我一样,喜欢的是编写程序,编写符合需求业务的程序,而不是一句句的if+for代码.

这里就举个小例子,例如把单元格区域的某一列添加到一个字典里面,这样的代码是不是写到想吐呢?我就大概写了两个类,就可以像下面的调用:
  1. var dict= wrk.UsedRange.ToValueArray().GetColumnValues(1).ToDictionary(v=>v);
复制代码

注意,上面的一句代码就实现了刚刚说的” 把单元格区域的某一列添加到一个字典里面”,其中其实只有两个方法(ToValueArray和GetColumnValues)是我自己添加的,其他的方法都是本身有的.而且其中还把单元格区域的值直接放到二维数组使用了(就像vba一样).只要是Range类的对象,都可以像上面的那样使用.

如果我把通用的类写到一个类库项目,那么以后的新的项目,只需要我引用,就可以这样使用了.当然,可以设计实现更复杂的需求,例如把两列加入字典,把某些行根据某些条件过滤之后才加入字典.调用的时候也是跟上面一样,一句代码.

其实上面的例子重点不是在于调用的时候是否只有一句的代码,重点在于调用代码本身非常明显清晰展示业务逻辑,相信不需要注释就可以表达.这些其实是面向方面的编程思想.面向过程和面向对象也是同样的目的.希望本帖可以让大家学到编写属于自己的库的能力,那个时候就是大家发挥想象力的时候了.

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-3-7 15:19 | 显示全部楼层
本帖最后由 excelhomesnake 于 2016-3-7 17:48 编辑

找说明例子是最困难的.为了适宜这里厚重的VSTO气氛,就找一个这板块的一个问题贴来举例子.

原贴是这里:http://club.excelhome.net/thread-1261490-1-1.html
问题核心大概是,如何比对两列数据的差异(差集,交集等等).

这里我们关注的是封装,那么转换一下功能用例大概如下:
1,把一块单元格区域转换为二维数组,可以方便管理数组数据和快速操作(查询和修改)这个数组
2,可以单独获取数组的其中一列,然后做各种对比操作.


简单分析上面的用例中的事物(名词),暂时定下一个核心领域类"单元格区域数组",取名为RangeArray为了可以在多个项目重用代码,那么就新建一个类库项目,然后做以下事情:
1,添加officePIA的引用.因为我们至少需要使用office库中的Excel的Range对象
2,添加一个代码文件,创建一个类

上述的点1的操作大概如下:
1,在"解决方案管理器中,鼠标右键类库项目中的<引用>项,选<添加引用>,在 <程序集>页下的<扩展>中,找到excel的库,勾选,并确定"

添加excel库引用1

添加excel库引用1


添加excel库引用2

添加excel库引用2


RangeArray类代码,如下:

注意:由于里面要使用Range类型,因此要using导入Range类型所在的命名空间,这里我使用别名
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;

  5. using excel = Microsoft.Office.Interop.Excel;

  6. namespace ClassLibrary_ExcelHelper
  7. {
  8.     public class RangeArray
  9.     {



  10.     }
  11. }
复制代码


现在应该往RangeArray类里面添加什么属性,方法好呢?一切用例驱动,简单分析之前的用例,如下:
  • 输入的是一个单元格区域,这里就是Range对象.既然如此,那么我们就规定使用RangeArray类的对象的时候,必须先提供一个单元格区域对象.因此写一个包含一个Range类型参数的构造方法.
  • 需要一个二维数组的变量去保存数据
  • 构造方法中,就把单元格区域赋值到二维数组中.


代码如下:
  1. namespace ClassLibrary_ExcelHelper
  2. {
  3.     public class RangeArray
  4.     {

  5.         private object[,] _valuesArray = null;

  6.         /// <summary>
  7.         /// 这个是构造方法
  8.         /// </summary>
  9.         /// <param name="range"></param>
  10.         public RangeArray(excel.Range range)
  11.         {
  12.             RangeToArray(range, _valuesArray);
  13.         }

  14.         /// <summary>
  15.         /// 把单元格区域的内容放到二维数组的过程
  16.         /// </summary>
  17.         /// <param name="range"></param>
  18.         /// <param name="array"></param>
  19.         private void RangeToArray(excel.Range range, object[,] array)
  20.         {
  21.             //单元格区域只包含一个单元格,也要保证成功赋值
  22.             if (range.Count == 1)
  23.             {

  24.                 array = (object[,]) Array.CreateInstance(typeof(object), new int[] { 1, 1 }, new int[] { 1, 1 });

  25.                 array[1, 1] = range.Value2;
  26.             }
  27.             else
  28.             {
  29.                 array = range.Value2;
  30.             }


  31.         }




  32.    

  33.     }
  34. }
复制代码


有几点需要注意的:
  • RangeArray的定义中,必须要写出权限关键字Public(对其他程序集公开),不然默认是Internal(只对自己的程序集公开).因为这个类库以后会让其他的vsto项目所引用.
  • 跟vba大同小异,单元格区域赋值到二维数组中,里面的每个元素都是object类型,因此必须要使用类型是二维object数组才可以.这里用object[,]表示二维
  • 当单元格的区域只有一格的时候,就自己创建一个二维数组,行列索引都是1基(最小下标为1).这里使用Array类的静态方法CreateInstance来创建



继续添加一些关于数组的基本信息(行列数),如下:
  1.         public int RowsCount
  2.         {
  3.             get
  4.             {
  5.                 return _valuesArray.GetLength(0);
  6.             }
  7.         }

  8.         public int ColumnsCount
  9.         {
  10.             get
  11.             {
  12.                 return _valuesArray.GetLength(1);
  13.             }
  14.         }
复制代码


此外,弄一个方法,可以从数组中获取某个位置(行列索引)的元素,如下:
  1.         public string GetValueAsString(int row, int column)
  2.         {

  3.             ThrowIndexOutOfRangeException(_valuesArray, row, column);

  4.             return _valuesArray[row, column].ToString();
  5.         }

  6.         public double GetValueAsDouble(int row, int column)
  7.         {

  8.             string valueString = this.GetValueAsString(row, column);

  9.             //如果值不能转换为数值,报错
  10.             double value;

  11.             if (double.TryParse(valueString, out value))
  12.             {
  13.                 return value;
  14.             }
  15.             else
  16.             {
  17.                 throw new InvalidCastException("获取的数组值不是一个有效数值");
  18.             }

  19.         }
复制代码


到此为止,已经构建了一个基本可用的类,它可以管理由单元格区域到数组的数据操作.附上目前为止的代码文件.
RangeArray.rar (1.07 KB, 下载次数: 27)

(续)




您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-5-22 13:13 , Processed in 0.035573 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表