精华内容
下载资源
问答
  • 作为一个被称作「超级表格」的表格,怎么可能没有函数设置呢?超级表格的函数一点都不复杂,可以说非常简单实用。函数有什么用?函数的使用可以大大降低时间成本,提升工作效率。我们可以通过设置函数,来让表单、...

    作为一个被称作「超级表格」的表格,怎么可能没有函数设置呢?

    超级表格的函数一点都不复杂,可以说非常简单实用。

    函数有什么用?

    函数的使用可以大大降低时间成本,提升工作效率。我们可以通过设置函数,来让表单、以及表格的提交变得更加便捷。

    您可以扫描一下二维码,登录后,就可以看到超级表格「函数」的神奇之处。

    blob.png

    也可以直接看下面的图片,这是小编用自己的手机扫描的。

    8B67A06EB252AD42E780F99FD056D240.png

    这个表单的每一个字段都设置了函数。所有的信息无需手动输入,扫码登录后都可以自动出现。(ps:账号信息需要你在当前软件中登录自己的超级表格账号才能显示)

    函数就可以用在例如:打卡签到记录时间、记录填写人账号信息等等信息。

    如何设置函数值?

    1、列属性设置

    您可以打开相应列的「列属性设置」,进入设置界面。

    0015719f5859b51f7b3cc2e463c8d00

    2、默认值

    在界面里有一个「默认值」输入框,一般来说,您可以在其中输入任何一个文字或者数字等,它会作为默认值出现在表单/表格里。但你也可以把「函数」填写在这里。可以点击「默认值」右侧的问号,来查看所有的函数。

    8S48``NR0S5@84QA2M[J)FK.png

    3、函数

    超级表格所有的函数都在这里,比如登录账户「loginuser()」和日期「today()」等等,您只需把它复制过来,填写进默认值里面就可以了。

    默认值123.jpg

    函数不仅对表单适用,同时也对表格适用。

    你可以任意设置,超级表格极高的自由度满足你随心所欲的愿望。


    展开全文
  • 可以看到我们所面对的表格具有特殊性和复杂性,表格线为虚线,且存在错位情况。在这种情况下想要准确检测出表格区域,并不是容易的事。 我们需要对这种原始图像做较多的预处理,以达到去掉文字干扰的目的,下次的...

    处理对象——虚线表格

    把之前做研电赛的东西做一点小的分享,先给大家看一下所处理的对象。可以看到我们所面对的表格具有特殊性和复杂性,表格线为虚线,且存在错位情况。在这种情况下想要准确检测出表格区域,并不是容易的事。

    在这里插入图片描述
    我们需要对这种原始图像做较多的预处理,以达到去掉文字干扰的目的,下次的博客可以再对这块进行一个细致的说明。
    我制作了一张预处理之后的图片来做算法测试。
    在这里插入图片描述

    处理方法——角点检测

    角点检测作为图像处理中对于特征提取与检测的重要方式之一,具有非常广泛的应用空间。
    角点的具体描述可以有几种:

    1. 一阶导数(即灰度的梯度)的局部最大所对应的像素点;
    2. 两条及两条以上边缘的交点;
    3. 图像中梯度值和梯度方向的变化速率都很高的点;
    4. 角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。
      角点检测中常用的算法有Harris角点检测和Shi-Tomasi 角点检测算法。Shi-Tomasi 算法是对Harris的改进,今天主要分享Harris算法的运用。

    Harris角点检测

    当一个窗口在图像上移动,在平滑区域如图(a),窗口在各个方向上没有变化。在边缘上如图(b),窗口在边缘的方向上没有变化。在角点处如图©,窗口在各个方向上具有变化。Harris角点检测正是利用了这个直观的物理现象,通过窗口在各个方向上的变化程度,决定是否为角点。
    在这里插入图片描述

    将图像窗口平移[u,v]产生灰度变化E(u,v)
    在这里插入图片描述
    由:在这里插入图片描述
    得到:
    在这里插入图片描述

    对于局部微小的移动量 [u,v],近似表达为:

    在这里插入图片描述

    其中M是 2*2 矩阵,可由图像的导数求得:

    在这里插入图片描述

    E(u,v)的椭圆形式如下图:
    在这里插入图片描述

    定义角点响应函数 R 为:
    在这里插入图片描述

    Harris角点检测算法就是对角点响应函数R进行阈值处理:R > threshold,即提取R的局部极大值。

    函数解读

    C++:

    void cornerHarris(InputArray src,//输入的原图Mat类型,需要为单通道8位或者浮点型图像
    				  OutputArray dst, //存放Harris角点检测的输出结果,和原图片有一样的尺寸和类型;
    				  int blockSize, //表示邻域的大小,更多详细信息在cornerEigenValsAndVecs()中讲到;
    				  int ksize,//表示Sobel()算子的孔径的大小; 
    				  double k, //Harris参数;通常是0.04
    			      int borderType=BORDER_DEFAULT)//图像像素的边界模式。注意它有默认值BORDER_DEFAULT;
    

    我的代码如下,你需要先配置好opencv到VS中,具体操作可以看我之前的博客;

    #include<opencv2/opencv.hpp>
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2\imgproc\types_c.h>//opencv4所不一样的地方
    #include <iostream>
    
    using namespace cv;
    using namespace std;
    
    
    Mat image;
    Mat imageGray;
    int thresh = 170;
    int MaxThresh = 255;
    
    void Trackbar(int, void*);  //阈值控制
    
    int main()
    {
    	image = imread("4.jpg");
    	cvtColor(image, imageGray, CV_RGB2GRAY);
    	GaussianBlur(imageGray, imageGray, Size(5, 5), 1); // 滤波
    	namedWindow("Corner Detected");//,CV_WINDOW_AUTOSIZE
    	createTrackbar("threshold:", "Corner Detected", &thresh, MaxThresh, Trackbar);
    	imshow("Corner Detected", image);
    	Trackbar(0, 0);
    	waitKey();
    	return 0;
    }
    
    void Trackbar(int, void*)
    {
    	Mat dst, dst8u, dstshow, imageSource;
    	dst = Mat::zeros(image.size(), CV_32FC1);
    	imageSource = image.clone();
    	cornerHarris(imageGray, dst, 9, 5, 0.04, BORDER_DEFAULT);
    	normalize(dst, dst8u, 0, 255, CV_MINMAX);  //归一化
    	convertScaleAbs(dst8u, dstshow);
    	imshow("dst", dstshow);  //dst显示
    	for (int i = 0; i<image.rows; i++)
    	{
    		for (int j = 0; j<image.cols; j++)
    		{
    			if (dstshow.at<uchar>(i, j)>thresh)  //阈值判断
    			{
    				circle(imageSource, Point(j, i), 2, Scalar(0, 0, 255), 2); //标注角点
    				cout << Point(j, i);
    			}
    		}
    	}
    	rectangle(imageSource, cvPoint(69, 49), cvPoint(440, 603), cvScalar(0, 0, 255), 2, 4, 0);
    	imshow("Corner Detected", imageSource);
    }
    

    处理结果

    在这里插入图片描述
    可以看到在阈值设定合适的情况下,对角点的检测效果还是比较客观的,但阈值的设定存在一定困难,面对不同的图容易出现如下情况,将粗的直线认为是矩形从而检测出过多的角点,我认为为了避免这类情况需要在预处理阶段做出更多干预处理。下一篇博客分享
    在这里插入图片描述
    参考博客:https://blog.csdn.net/qq_27396861/article/details/87898892
    https://blog.csdn.net/xiaowei_cqu/article/details/7805206

    展开全文
  • 文章目录HTML+css基础链接标签自定义列表文本格式化标签表格合并单元格CSS选择器CSS继承问题标签表现形式块元素内容由宽度实现背景图片属性png/jpg 区别CSS Sprite溢出文字省略号显示显示与隐藏边框透明浮动...

    HTML+css基础

    链接标签

    <a href="跳转目标" target="目标窗口的弹出方式">文本或图像</a>
    

    href:用于指定链接目标的 url 地址,当为标签应用 href 属性时,它就具有了超链接的功能。 Hypertext Reference 的缩写,意思是超文本引用。

    target:用于指定链接页面的打开方式。

    • _self 为在当前窗口打开(默认值)。

    • _blank 为在新窗口中打开方式。

    自定义列表

    自定义列表常用于对术语或名词进行解释和描述,自定义列表的列表项前没有任何项目符号。其基本语法如下:

    名词1
    名词1解释1
    名词1解释2
    ...
    名词2
    名词2解释1
    名词2解释2
    ...

    文本格式化标签

    • 上标/下标 <sup> <sub>

    • 下划线/删除线 <ins> <del>

    • 引用文本 <blockquote> (长引用)<q>(短引用)

    • 转义字符

      空格 &nbsp; &#160;

      小于号 &lt; &#60;

      大于号 &gt; &#62;

      和符号& &amp;

      版权© &copy;

      注册商标® &reg;

      商标™ &trade;

    表格

    ... ... ...
    表头内的文字
    单元格内的文字

    合并单元格

    • rowspan 单元格所占行
    • colspan 单元格所占列

    CSS

    选择器

    • 复杂选择器

      • 交集选择器:: 可以同时使用多个选择器,这样可以选择同时满足多个选择器的元素。

        语法:选择器1选择器2{ } 没有空格

      • 并集选择器 : 可以同时使用多个选择器,多个选择器将被同时应用指定的样式。
        语法: 选择器1,选择器2,选择器3 { } 逗号隔开

      • 后代选择器

        语法 选择器1 选择器2{} 有空格

    CSS的继承问题

    给父元素设置的样式 ,子元素也会生效(继承)

    可继承 字体相关(大小,颜色) ,文本相关(对齐方式,行高)

    不可继承 a 标签 字体颜色 不会继承父元素

    想修改a标签的颜色 ,必须选到a标签

    标签的表现形式

    • 块级标签(元素) [div p 标题标签 table tr ul li dl等]

      • 可以设置宽高
      • 换行展示
      • 不写宽度,宽度是父元素的百分百
    • 行内元素[a span strong del ins em i b]

      • 同行展示
      • 设置宽高无效
      • 不写宽度,宽度由内容撑开
    • 行内块元素[input button img]

      • 同行展示
      • 设置宽高有效
      • 不写宽高,宽高由内容撑开

    块元素的内容由宽度实现

    width:fit-content;

    背景图片属性

    属性名称 属性作用
    background-color 背景图片颜色 color
    background-image 背景图片 url(‘1.png’)
    background-repeat 平铺方式 repeat 、no-repeat、repeat-x、repeat-y
    background-position 图片位置 left、 right、 top、 bottom、 center
    background-attachment 背景滚动 scroll、fixed (注意:基于 body 的定位)
    background 简写(顺序不能错) background: green url(1.jpg) no-repeat center fixed;

    png/jpg 区别

    • jpg 背景不透明/png 背景透明
    • jpg 适合色彩丰富的图片
    • png 适合单色图片

    CSS Sprite

    CSS Sprites也叫CSS精灵、CSS雪碧图,是一种网页图片应用处理方式。

    CSS Sprites(图片整合技术) 的目的就是通过整合图片,减少对服务器的请求数量,从而加快页面加载速度。

    溢出文字省略号显示

    white-space:nowrap;
    
    overflow: hidden;
    
    text-overflow:ellipsis;
    

    显示与隐藏

    display:none; 隐藏 不占据位置,下方元素会上移.

    display:不为none ;显示

    visibility:hidden;隐藏 依然占据位置,下方元素不会上移

    visibility:vsible;显示

    opacity:0;隐藏

    opacity:1;显示

    边框透明

    border: 1px solid transparent;

    背景色默认蔓延到 边框 区域

    background-clip: content-box;

    裁减掉内容区外的颜色不显示

    提前把边框做好,透明,hover时,边框就可以显示出来

    浮动

    浮动的表现形式及影响

    1. 元素浮动之后,脱离文档流,不再在文档六中占据位置,下方的元素会上移
    2. 元素浮动之后,下方元素会上移,但是 里边的文字 会环绕在浮动元素周围(浮动元素不会和文字重叠)
    3. 元素浮动之后 ,如果没写宽度,宽度由内容决定 ,所以,一般我们都会为 浮动元素 指定一个宽度.
    4. 元素浮动以后即完全脱离文档流,这时不会再影响父元素的高度。 也就是浮动元素不会撑开父元素。父元素高度丢失,下方的元素 布局就开始混乱.
    5. 行内元素浮动后,就可以设置宽高了

    解决浮动的影响

       1. 严格计算父类元素的高度
       2. 假如无法准确确定父元素高度,给父类元素 添加overflow:hidden,那么里边的浮动元素就能撑起高度了
       3. 在所有浮动元素之后,追加一个 空的 块元素,然后对其设置 clear:both **不推荐 语义化太差**
       4. 使用after伪元素清除浮动(推荐使用)
        .clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/
            content: "";
            display: block;
            height: 0;
            clear:both;
            visibility: hidden;
        }
        .clearfix{
            *zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
        }
     
    <body>
        <div class="fahter clearfix">
            <div class="big">big</div>
            <div class="small">small</div>
            <!--<div class="clear">额外标签法</div>-->
        </div>
        <div class="footer"></div>
       5.使用before和after双伪元素清除浮动
         .clearfix:after,.clearfix:before{
            content: "";
            display: table;
        }
        .clearfix:after{
            clear: both;
        }
        .clearfix{
            *zoom: 1;
        }
     
     <div class="fahter clearfix">
            <div class="big">big</div>
            <div class="small">small</div>
        </div>
        <div class="footer"></div>
    

    行内元素的边距问题

    行内元素的上下方向的paddingmargin不起实质性作用

    定位

    一个元素开启定位之后 ,元素特性会改变

    1. 脱离文档流,不再占据位置,下方元素会上移

    2. 开启定位之后,元素如果不写宽度,宽度会由 内容决定

    3. 脱离文档流,无法再撑起 父元素的高度

    4. 行内元素 定位之后,可以设置 宽高了

    **上特性改变 只针对 绝对定位 和 固定定位 **

    相对定位 元素 特性不发生任何改变 ,也不会脱离文档流

    所以一般不用相对定位 去 描述元素的位置,一般用于打辅助(辅助绝对定位用来给父元素添加定位属性,使其能够成为一个参照物

    BFC

    了解bfc的用途 详细见面试题总结

    CSS3新增

    子代选择器

    div > p 选择 div的子元素p标签(必须是亲儿子,不隔代)

    紧邻兄弟选择器

    + 选择下一个(紧挨着的)符合条件的兄弟元素

    通用兄弟选择器

    ~ 选择后边所有符合条件的兄弟元素

    伪类选择器

    除了以前学过的
    :link 链接未被访问时
    :active 链接点击时(一瞬间)
    :visited 链接访问后
    :hover 鼠标悬浮时

    冒号前面不能有空格

    CSS3又新增了其它的伪类选择器

    表单相关伪类

    :checked 匹配被选中的选项
    :focus 匹配获焦的输入框

    目标伪类

    E:target 结合锚点进行使用,处于当前锚点的元素会被选中

      <style>
      	li:target{
      		font-size: 30px;
      		color: blue;
      	}
      <style>
      <body>
      	<a href="#li3">点我</a>
      	<li id="li3">li3</li>
      </body>
    

    伪元素
    E::beforeE::after 默认行内元素 content 属性必须写
    E::first-letter文本的第一个字母或字
    E::first-line 文本第一行
    E::selection 被选中的文本

    ":" 与 “::” 用于区分伪类和伪元素

    JS基础

    变量

    变量的命名规则

    1.只能使用 字母 数字 _ $

    2.不能以数字开头

    3.格区分大小写

    1. 不能使用js中的 关键词或者保留字(就是已经征用的词语比如 var)

    2. 使用驼峰命名(多个单词时,后边单词的首字母大写) 如firstName getMax

    3. 命名语义化 (见名知意)

    基本数据类型

    1.字符串 (引号引起来)

    2.数字 (NaN是一个特殊的数字)

    3.布尔 (只有true和false两个值)

    4.undefined

    5.null

    复杂数据类型

    数组 对象 函数

    判断数据类型方法

    typeof

    数据类型之间的相互转换

    其他类型转成字符串

    1.利用String() 可以把 括号里边的 值转成 字符串类型

    1. 其他数据类型转成字符串的时候 ,就是在 原始数据上 加了 一个 引号

    2. 隐式转换 采用的 就是 String() 的规则

    其他类型转成数字

    Number()

    只有纯数字的字符串转成数字 只要含有非数字字符串,都会转成**NaN**

    true==>1 false==>0

    undefined==>NaN

    null==>0

    其他类型转成布尔类型

    Boolean()

    转成false的情况下只有以下5种,其他都转成true

    1.空字符串

    2.0

    3.NaN

    4.undefined

    5.null

    自增和自减运算

    b=b+1可以简写成b++ 或者++b;b=b-1可以简写成b-- 或者–b;

    • 相同点:不管是 b++ 还是 ++b 都实现了 b的 自增1

    • 不同点: 当用一个变量接收 b++或者 ++b的结果时,

       var m = 20;
    
        var n = m++;
    
       console.log(m); // 21
    
        console.log(n); // 20
    
        var x = 20;
    
        var y = ++x;
    
        console.log(x); // 21
    
       console.log(y); // 21
    

    ​ 虽然有不同点 ,但是 一般开发的时候 ,都是为了 实现b自增1 ,所以 b++ 和 ++b 都可以

    Math对象

    随机[m,n]之间的整数 m,n为整数

    Math.floor(Math.random()*(n-m+1)+m)

    随机数[min,max]

    Math.floor(Math.random()*(max-min+1))+min 标准

    数组

    数组的常用方法

    *都会改变原数组*
    arr.push('小张') 往后添加   返回值新数组的长度
    arr.unshift('小明') 往前添加  返回值新数组的长度
    arr.pop() 从后删除  返回值删除的元素
    arr.shift() 从前删除  返回值删除的元素
    arr.splice() 删除元素 [起始索引,删除个数]
    
    
    
    *不会改变原数组*
    concat() 两个数组的合并(连接)
    join() 数组转换为字符串(括号内可以指定连接符,不写默认逗号隔开)
    split()  字符串变为字符串数组 (括号内指定以哪个字符隔断)
    slice() 实现对数组的截取 [起始索引,结束索引)左闭右开
    indexOf() 获取括号中的元素在数组中的索引 返回值=-1 说明数组中不存在此元素
    
    
    

    字符串方法

     concat() 连接字符串
     charAt() 获取相应位置的字符
     charCodeAt() 获取相应位置的Unicode编码 
     indexOf() 返回字符在字符串中的位置
     lastIndexOf() 倒着查找字符
     slice() 截取字符串  
     substr() 截取字符串 第一个参数开始位置 第二个数参数截取个数
     toUpperCase()   变大写
     toLowerCase()  变小写
    

    取相应位置的 Unicode 编码

    函数

    函数用来保存代码(封装代码),可以让代码重复利用

    创建函数

    方式一:关键字创建 具名函数

    function foo (){
    }
    
    

    方式二:匿名函数表达式

    var bar=function(){
    }
    
    

    方式三:自执行函数

    ;(function(){
    })()
    
    

    对象

    json对象

    JSON.stringify() 可以把对象转成json字符串

    JSON.parse() 只可以把json字符串 转回对象

    arguments对象

    函数的实参对象,里边有所有的实参信息; 只能在函数内部使用,是一个数组形式(类数组/伪数组) ,具备索引和长度但是没有数组的方法

    防抖和节流

    防抖(debounce

    所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间

    节流(throttle

    **所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。**节流会稀释函数的执行频率。

    对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。

    https://www.jianshu.com/p/c8b86b09daf0

    实例见面试题总结

    组件添加原生点击事件

    @click.native 不加native 点击事件不生效

    深浅拷贝

    链接:https://segmentfault.com/a/1190000018874254

    几个思维导图

    vue组件之间如何传值通信

    父到子:

    ​ 1)在子组件的标签上,动态绑定自定义属性, 把需要传给子组件的值赋给该属性

    ​ 2)需要在子组件的props属性上定义一下这个属性

    子组件修改父组件传来的值:

    this.$emit(‘update:要改变的值’,改变后的值 )

    子到父:

    ​ 1)找到发射事件时机(例如点击事件),发射事件 this.$emit(‘要发射的事件’,要传递的值)

    ​ 2)在子组件的标签上绑定要发射的事件(发射的事件不能用驼峰)

    ​ 3)在父组件中注册这个事件 (该事件接收的参数即为传递的值)

    兄弟组件:

    ​ 利用中央事件总线 bus emitemit推送,on接收

    ​ //var bus = new Vue()

    ​ 或者绑到原型链上

    Vue.prototype.$bus = new Vue();

    传递: this.bus.bus.emit(‘一个标识符’,要传递的值);

    接收: this.bus.bus.on(‘一个标识符’, val => {

    ​ val就是传过来的值

    ​ })

    展开全文
  • 说明:因为Markdown下维护这样复杂的表格一点麻烦,故,这里以图片形式展示出来,如后续内容有更新,请点击 这里 访问原始笔记链接。为知笔记 的表格渲染在移动端表现不佳,为了获得更好的阅读体验,请在电脑端...

    C# 版本历史记录

    从 C# 1.0 到 C# 9.0,历代 C# 语言特性一览.png

    说明:因为Markdown下维护这样复杂的表格有一点麻烦,故,这里以图片形式展示出来,如后续内容有更新,请点击 这里 访问原始笔记链接。为知笔记 的表格渲染在移动端表现不佳,为了获得更好的阅读体验,请在电脑端访问查看。

    C# 版本特性说明

    现在是 2021 年,相信 C# 7.0 以前的版本大家都应该没有什么问题,因为像博主这样的 90 后“中年”男人,接触的都是这个版本的 C#。所以,在这里我们主要讲解大家C# 7.0、8.0 以及 9.0 的语法特性。考虑到文章篇幅有限,这里选取的都是博主个人比较喜欢的语法特性,如果这里没有你喜欢的特性,请参考文章末尾的参考链接。如果这里的特性你都不喜欢,请你马上关掉这个网页,愿这个世界:Love & Peace。可能你会感觉到我说话变得小心翼翼起来,因为这个世界上有种叫做“杠精”的生物,当它从我的只言片语里读出那些挫败感的时候,终于有了嘲笑我们这批步入30岁行列的90后的底气,没错,我在最近的博客评论中被读者“嘲讽”了,让暴风雨来得更猛烈一些吧!

    C# 7.0

    在 C# 7.0 中,我个人比较喜欢的特性主要有以下几个:元组和弃元更多的 expression-bodied 成员out 变量异步 Main 方法模式匹配引发表达式

    元组和弃元

    这个概念乍听起来可能会有一点陌生,其实,按我的理解,这就是增强的元组语法,终于可以摆脱Item1Item2…啦:

     //示例1
    (string Alpha, string Beta) namedLetters = ("a", "b");
    Console.WriteLine($"{namedLetters.Alpha}, {namedLetters.Beta}");
     //示例2
    var alphabetStart = (Alpha: "a", Beta: "b");
    Console.WriteLine($"{alphabetStart.Alpha}, {alphabetStart.Beta}");
    //示例3
    int count = 5;
    string label = "Colors used in the map";
    var pair = (count, label);
    Console.WriteLine(pair);
    

    有一段时间,前端同事总和我吹嘘 ES6 里面的解构多么多么好用!对此,我想说,C# 一样可以解构,假设我们现在有下面的一个方法:

    static (string, double, double) GetLocation() 
     {
        var city = "西安市";
        var lat = 33.42d;
        var lon = 107.40d;
        return (city, lon, lat);
    }
    

    这就是简化后的元组的用法,如果是以前,我们还需要返回一个Tuple<string, double, double>。此时,如果我们需要解析城市名称及其经纬度,可以这样做:

    //示例4
    (string city, double lon, double lat) = GetLocation();
    Console.WriteLine($"{city},({lon},{lat})");
    

    OK,那么什么又是弃元呢?继续以上面的代码为例,如果我不关心经纬度,只需要城市名称又该怎么办呢?人家的方法返回的是一个3元的结果,而我们只需要其中的1元,此时,就有了所谓弃元的概念:

    (string city, _, _) = GetLocation();
    Console.WriteLine($"{city}");
    

    在 C# 中可以使用下划线_来表示要舍弃的元,是为弃元,怎么样?你学会了吗?

    更多的 expression-bodied 成员

    这部分同样是经过强化的 Lambda 表达式,之前我们可以在成员函数和 只读属性上使用 Lambda 表达式,而现在,我们可以将其运用在构造函数终结器以及 getset访问器:

    // Expression-bodied constructor
    public ExpressionMembersExample(string label) => this.Label = label;
    
    // Expression-bodied finalizer
    ~ExpressionMembersExample() => Console.Error.WriteLine("Finalized!");
    
    private string label;
    
    // Expression-bodied get / set accessors.
    public string Label
    {
        get => label;
        set => this.label = value ?? "Default label";
    }
    

    out变量

    个人认为,这是一个非常不错的改进,终于不用再单独声明out变量啦:

    if (int.TryParse(input, out int result))
        Console.WriteLine(result);
    else
        Console.WriteLine("Could not parse input");
    

    异步 Main 方法

    顾名思义,Main 方法现在可以支持 async 关键字啦:

    static async Task<int> Main()
    {
        // This could also be replaced with the body
        // DoAsyncWork, including its await expressions:
        return await DoAsyncWork();
    }
    

    在没有返回值的情况下,可以考虑返回Task:

    static async Task Main()
    {
        await SomeAsyncMethod();
    }
    

    模式匹配

    主要是针对 isswitch 语句提供了增强的语法。在这里,对于前者来说,我们可以将判断和赋值两个步骤合二为一:

    public static double ComputeAreaModernIs(object shape)
    {
        if (shape is Square s)
            return s.Side * s.Side;
        else if (shape is Circle c)
            return c.Radius * c.Radius * Math.PI;
        else if (shape is Rectangle r)
            return r.Height * r.Length;
        // elided
        throw new ArgumentException(
            message: "shape is not a recognized shape",
            paramName: nameof(shape));
    }
    

    而对于后者来说,主要打破了传统 switch 语句的常量模式:

    public static double ComputeArea_Version3(object shape)
    {
        switch (shape)
        {
            case Square s when s.Side == 0:
            case Circle c when c.Radius == 0:
                return 0;
    
            case Square s:
                return s.Side * s.Side;
            case Circle c:
                return c.Radius * c.Radius * Math.PI;
            default:
                throw new ArgumentException(
                    message: "shape is not a recognized shape",
                    paramName: nameof(shape));
        }
    }
    

    引发表达式

    这个主要是针对 throw 关键字的增强,当我看到微软的文档的时候,我突然意识到,这个语法其实我用了很久啦!

    //场景A:条件运算符
    string arg = args.Length >= 1 ? args[0] :
        throw new ArgumentException("You must supply an argument");
    //场景B:Null合并运算符
    public string Name
    {
        get => name;
        set => name = value ??
            throw new ArgumentNullException(
              paramName: nameof(value), 
              message: "Name cannot be null");
    }
    //场景C:Lambda表达式
    DateTime ToDateTime(IFormatProvider provider) =>
        throw new InvalidCastException("Conversion to a DateTime is not supported.");
    

    以上,就是 C# 7.0 中我个人比较喜欢的语法特性。需要了解所有 C# 7.0 语法特性的小伙伴们,则可以参考这里:C# 7.0 - C# 7.3 中的新增功能

    C# 8.0

    在 C# 8.0 中,我个人比较喜欢的特性主要有以下几个:默认接口方法异步流索引和范围

    默认接口方法

    关于这个,我觉得有点多此一举,如果一定要有一个默认行为,那你用继承来实现不就好啦,接口本来就是用来实现的啊摔!

    public class ChineseSayHello : ISayHello
    {
        public string Who { get; set; }
    }
    
    public interface ISayHello
    {
        private const string DefaultPersopn = "Anumouse";
        string Who { get; set; }
        void SayHello()
        {
            Who = DefaultPersopn;
             Console.WriteLine($"Hello, {Who}");
        }
     }
    

    在上面这个例子里,ChineseSayHello没有实现SayHello()方法不影响编译,因为ISayHello有默认实现,可正因为如此,SayHello()方法属于ISayHello,不属于ChineseSayHello

    //正确,可以编译
    var sayHello = new ChineseSayHello() as ISayHello;
    sayHello.SayHello();
    //错误,无法编译
     var sayHello = new ChineseSayHello();
    sayHello.SayHello();
    

    异步流

    该特性可以看作是IEnumerable<T>的一个延伸,即IAsyncEnumerable<T>,主要有下面三个属性:

    • 它是用 async 修饰符声明的。
    • 它将返回 IAsyncEnumerable。
    • 该方法包含用于在异步流中返回连续元素的 yield return 语句。

    下面是一个来自微软官方的基本示例:

    //生成异步流
    public static async System.Collections.Generic.IAsyncEnumerable<int> GenerateSequence()
    {
        for (int i = 0; i < 20; i++)
        {
            await Task.Delay(100);
            yield return i;
        }
    }
    //枚举异步流
    await foreach (var number in GenerateSequence())
    {
        Console.WriteLine(number);
    }
    

    和异步流相关的一个概念是:异步可释放,即 System.IAsyncDisposable,这个可以参考:实现 DisposeAsync 方法

    索引和范围

    关于这个,我们换一种说法,可能大家就能接受啦!是什么呢?答案是:切片。切片语法博主经常在 Python 中使用,想不到有生之年居然可以在 C# 里用到这个语法。不过,这个语法糖怎么看都不甜啊,因为没那味儿!

    var words = new string[]
    {
                    // index from start index from end
        "The", // 0 ^9
        "quick", // 1 ^8
        "brown", // 2 ^7
        "fox", // 3 ^6
        "jumped", // 4 ^5
        "over", // 5 ^4
        "the", // 6 ^3
        "lazy", // 7 ^2
        "dog" // 8 ^1
    };  
    //取最后一个元素
    Console.WriteLine($"The last word is {words[^1]}");
    //获取第一个元素到第三个元素
    var quickBrownFox = words[1..4];
    //获取倒数第一个元素到倒数第二个元素
    var lazyDog = words[^2..^0];
    //获取全部元素
    var all = words[..];
    //获取开始到第三个元素
    var firstPhrase = words[..4];
    //获取结束到倒数第二个元素
    var lastPhrase = words[6..];
    

    看起来这些东西在 Python 里都有啊,到底是哪里除了问题呢?我觉得更多的是符号上的不同吧, ^ 这个符号除了表示指数的意思以外,还有按位进行异或运算的意思,所以,这个语法糖加进来以后就会显得相当混乱,而 .. 这个符号显然没有 : 写起来方便啊,所以,虽然 C# 从 C# 8.0 开始有了切片语法,可这不是我想要的切片语法啊!

    以上,就是 C# 8.0 中我个人比较喜欢的语法特性。需要了解所有 C# 8.0 语法特性的小伙伴们,则可以参考这里:C# 8.0 中的新增功能

    C# 9.0

    在 C# 9.0 中,我个人比较喜欢的特性主要有以下几个:Record顶级语句模式匹配增强

    Record

    record 是 C# 9.0 中提供的一个新的关键字,地位上等同于 classstruct,中文翻译为:记录类型。这是一种引用类型,它提供合成方法来提供值语义,从而实现相等性。 默认情况下,记录是不可变的。简而言之,record 是不可变的引用类型。你可能会说,我们为什么要搞这么一个类型出来呢?难道 class 不香吗?

    我觉得如果要回答这个问题,可以借鉴 DDD 中的实体值对象这两个概念。实体 通常都有一个唯一的标识并且在整个生命周期中具有连续性,这一类角色通过 class 来实现一直都工作得很好。例如,每一个 User 都会有一个唯一的UserId ,我们使用 UserId 来判断其相等性。而 值对象 则是指那些没有唯一的标识、不可变的、通过属性来判断相等性。例如,我们有一个地址 Address,它由省、市、区、县和详细地址组成,那么,问题来了,如果两个 Address 的省、市、区、县和详细地址都相同,这两个 Address 是不是同一个地址呢?常识告诉我们:不会,因为它们是不同的实例。

    这就是 record 出现的原因,对于上面的这个问题,我们可以来解决:

    record Address
    {
        public string Province { get; set; }
        public string City { get; set; }
        public string District { get; set; }
        public string County { get; set; }
    }
    
    var addr1 = new Address() { Province = "陕西省", City = "西安市", District = "雁塔区" };
    var addr2 = new Address() { Province = "陕西省", City = "西安市", District = "雁塔区" };
    Console.WriteLine($"addr1 == addr2:{addr1 == addr2}");
    

    想想以前我们是怎么做的呢?是不是要写类似下面这样的代码:

    if (addr1.Province == addr2.Province && addr1.City == addr2.City) {
    
        //属性太多啦,我就不一个一个地比较啦,懂得都懂
    }
    

    所以,这就是 record 存在的意义。除此之外呢,这个关键字更多的是语法层面上的,实际上从编译出来的 IL 来看,它本质上依然是一个类,并且它是不可变的。定义记录类型时,编译器会合成其他几种方法:

    • 基于值的相等性比较方法
    • 替代 GetHashCode()
    • 复制和克隆成员
    • PrintMembers 和 ToString()

    那么,你可能还会有疑问,假如我定义了两个不同的记录类型,它们都拥有相同的属性成员,如果按值相等来判断的话,岂不是这两个不同的记录类型变成相同的了?这么重要的问题,微软怎么可能没有想到呢?编译器会合成一个 EqualityContract 属性,该属性返回与记录类型匹配的 Type 对象。在这里,微软再一次发挥了元组的威力,对于上面定义的地址,我们可以继续使用解构语法:

    (province, city, district, county) = addr1;
    

    当然,我相信哪怕到2090年,这个世界上依然会有“杠精”:你说这玩意儿不能变?我就想变怎么办?答案是使用with语法:

    public record Person
    {
        public string LastName { get; }
        public string FirstName { get; }
    
        public Person(string first, string last) => (FirstName, LastName) = (first, last);
    }
    
    var person = new Person("Bill", "Wagner");
    Person brother = person with { FirstName = "Paul" }; // 修改FirstName的副本
    Person clone = person with { }; // 空集副本
    

    好了,关于记录类型就先为大家介绍到这里,更详细的说明可以参考这里:使用记录类型

    顶级语句

    顶级语句,这个又是一个听起来非常模糊的概念对不对? 大家可以看一下这篇文章:26 种不同的编程语言的 “Hello World” 程序。怎么样,在众多解释型的语言中,C#、Java 甚至 C++ 的 “Hello World” 是不是都看起来有一点臃肿?

    好了,现在可以梦想成真啦!

    using System;
    
    Console.WriteLine("Hello World!");
    

    如果觉得这样还显得臃肿,可以省略 using 部分:

    System.Console.WriteLine("Hello World!");
    

    当然啦,一个项目里显然只能有一个文件可以使用顶级语句,你可以理解为这些代码运行在一个看不见的Main()方法中,而Main()方法显然只能有一个,相比下来,Python 就自由多啦,不过if __name__ == '__main__'的老梗就不再这里展开啦!

    模式匹配增强

    感觉微软在模式匹配的道路上越走越远啊,说好的语法糖呢?这简直是毒药,7.0 里面眼花缭乱的switch都还没学会呢!

    public static bool IsLetter(this char c) =>
        c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';
    
    public static bool IsLetterOrSeparator(this char c) =>
        c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ',';
    
    if (e is not null)
    {
        // ...
    }
    

    以上,就是 C# 9.0 中我个人比较喜欢的语法特性。需要了解所有 C# 9.0 语法特性的小伙伴们,则可以参考这里:C# 9.0 中的新增功能

    参考链接

    展开全文
  • 1.废话不多说,直接上传模板 可以看到模板里面不仅包含文本框,表格,跨行,跨列,而且还有图片。 很头疼,没关系,在...图片比较复杂一点,构造模板时候,需要点击word工具上方插入图片。 然后另存为word2003...
  • 区块链中哈希函数

    2019-11-28 15:33:46
    小白如何秒懂区块链中的哈希计算 当我在区块链的学习过程中,发现有一个词像幽灵一样反复出现,“哈希”,英文写作“HASH”。 那位说“拉稀”同学你给我出去!...我最长的密码就是123456,复杂一点的...
  • 如此众多的表格功能可以让您无拘无束地制作出最富有个性的表格。  公式编辑应用广泛 WPS 2000 不仅可以快速编辑复杂的数学、化学方程式,在它的图文符号库中还有许多对象集和专业符号,如各种图形、公式单元、特殊...
  • 附件(关于2011年工作的一点浅见) 3 3 探讨一些技术问题 4 3.1 Frameset和iframe 4 3.2 Frameset和Div两种方式对比 5 3.2.1 frameset布局优点 5 3.2.2 frameset布局缺点 5 3.2.3 DIV传统布局与frameset相比...
  • Latex简易教程

    2021-02-26 10:37:41
    对于生成复杂表格和数学公式,这一点表现得尤为突出。因此它非常适用于生成高印刷质量科技和数学类文档。这个系统同样适用于生成从简单信件到完整书籍所有其他种类文档。1 PS:环境:Latex中
  • 项目需要样式比较复杂,刚开始因为时间比较紧所以采用了Itextpdf插件代码生成pdf ,实话说过程十分繁琐,因为pdf文件样式比较多,表格也比较多,各种的表格,还有就是页眉页脚页码都要自己找页面位置坐标但是又不能像...
  • 软件界面设计工具_3款合集

    千次下载 热门讨论 2010-06-29 03:52:47
    预制了六十多个界面元素,从简单输入框,下拉框,到经常用得到导航条,日历,表格,到复杂的Tag Cloud,Cover Flow, 地图,WYSWYG格式工具栏等,有了这些不用从头画起,其实比用白板都快; 界面元素修改很...
  • 对于生成复杂表格和数学公式,这一点表现得尤为突出。  基于TeX/LaTeX,也受Design ScienceWebEQ Editor等启示,我们与国外相关开源项目参与者一起,用我们自己方式,将TeX/LaTeX引入了网络,即合作开发了...
  • ipython-2.2.0

    2014-09-14 09:18:11
    在较新ipython版本中,添加了ipython notebook功能,弥补了ipython shell下代码不易保存等缺点,并且在使用 --pylab inline选项后,可以在代码执行后立即显示运行结果(包括图片,数据表格等),因此在数据分析...
  • Tcl_TK编程权威指南pdf

    热门讨论 2011-03-25 09:30:55
    它们提供了足够可编程特性(变量、流程控制和过程),使你可以将现有程序组装成符合自己需要的复杂的脚本程序。Shell程序非常适用于一些日常任务自动化处理工作。 Tcl解释器可以很容易地添加到你应用程序中,...
  • 注意到一点:其中 "created_at/updated_at" 不能生效, 是因为框架默认自动时间戳配置不同 > 5. 页面跳转方式要注意下,同时前者可以 __construct() 初始化判断 Session 数据,而后者不可 > 6. 等等等...
  • 目前为止CSS3还没有一套成熟规范,其中模块也在不断更新,特别是浏览器对CSS3特性支持也在不断变化,同时没有足够时间去学习和研究W3C官方文档和规范,致使我们学习CSS3变得更为复杂。 为什么会选择这个...
  • 最初,因为它在很大程度上仅把不同类型Office文档链接在一起,所以利用它,例如,可以把一个小型Excel电子表格放在Word文档中。之后,它逐步演化为COM、DCOM(Distributed COM,分布式组件对象模型)和最终COM+。...
  • iPhone开发秘籍(第2版)--源代码

    热门讨论 2012-12-11 13:51:22
    此外,还结合实例讲解了如何开发各种iphone特性,包括视图、视图控制器、警告、表格、媒体、控件、人物、位置和事件。  《iphone开发秘籍(第2版)》适合iphone和mac开发人员。 作译者 作者:(美国)萨丹(Erica ...
  • asp.net知识库

    2015-06-18 08:45:45
    我对J2EE和.NET的一点理解 难分难舍DSO(一) InternalsVisibleToAttribute,友元程序集访问属性 Essential .NET 读书笔记 [第一部分] NET FrameWorkCollections支持 .NET反射在软件设计上应用 关于跨程序集...
  • 在这里我要说明两点:1、我示例文件总是有A和B分别是用C#和VB写,演示的图片就用C#那一种,都一样嘛,教程里面代码也是写两种用分割开,大家可以比较一下。2、我写教程时候用都是记事本来编写APS.NET大家...
  • ASP.NET精品课程+源代码

    千次下载 热门讨论 2009-01-05 20:15:51
    积极参与,平等对话和研讨,从而重点培养学习者批判反思意识及团队协作能力,并促使学习者充分理解问题的复杂性、变化性、多样性等属性重要教学形式。目前大部分高校在网站建设、程序设计等教学中多采用传统...
  • Microsoft Visual FoxPro表格文件 DCT:Microsoft Visual FoxPro数据库容器 DCU:Delphi编译单元文件 DCX:Microsoft Visual FoxPro数据库容器;基于PCX传真图像;宏 DIR:MacromediaDirector文件 DLL:动态...

空空如也

空空如也

1 2
收藏数 22
精华内容 8
关键字:

复杂一点的表格图片