获取程序的编译时间

日常新需求

新的需求又来了。这次是程序在编译后6个月拒绝启动。BETA性质的软件都有类似的需求。但大部分软件要么是启动时检查更新,要么是联网判断是否过期。对于我们现在做的这个小工具太小题大做了。根据编译时间判断过期的需求看似奇葩,也是有点道理的。

C#

使用MSBuild编写构建脚本

背景

项目需求变更,需要从一份代码里编译出好几个不同的版本。编译和部署的复杂度都成指数增加,简单的Release构建搞不定了,写构建脚本迫在眉睫。

Build a (partial) self-contained WPF application

巨人的肩膀

新事物的产生总是与老事物有千丝万缕的联系。或是从中得到启发,或是对其全面改良。新事物的源头通常可以追溯到很久远的一些概念上。因此有了「站在巨人的肩膀上」 这样的说法。在程序设计里面,「巨人们的肩膀」 就是我们的应用程序使用的库了。踩在这些「巨人」们的肩膀上我们的程序才得以重见天日;为了实现一个库,有时候会使用到其他的库。我们所依赖的「巨人」又踩在了其他「巨人」的肩膀上,把依赖关系变成了树状结构,我们的程序处在根节点。

扯远了:)

引用类型的开销

值类型与引用类型

C#中的类型分为引用类型和值类型。使用structenum关键字修饰的类型定义是值类型,使用classdelegate关键字修饰的类型是引用类型。引用类型和值类型各有限制,分别适用于不同的场景。不同于C++,C#中的值类型只能分配在栈上*1,引用类型只能分配在GC堆上。C#中的GC是精确式GC,这就对GC堆上的指针有了一些要求。这是引用类型有开销的原因之一。

Sync block index 与 Type object pointer

读过C# vir CLR的同学会知道,引用类型的开销是Sync blockindex和Type object pointer。他们的长度是都是一个字长。即在32位CLR上是4字节,在64位CLR上是8字节。Sync block index在CLR中是用于实现lock,Monitor等线程同步原语,Type object pointer是指向当前对象运行时类型信息的一个指针。Sync block index与Type object pointer只在CLR层面存在,对C#程序来说是透明的。但是CLR将它们暴封装后露C#,例如线程同步原语和反射API。

面向抽象编程

Preface

说来惭愧,直到近几天才明白了一点面向对象设计的。给我带来启发的是SOLID中的D,它代表Dependency Inversion(依赖反转)。尽管写/背定义很无聊,但我还是想写一下依赖反转的核心

上层模块不应该依赖下层模块,他们都应该依赖抽象

Talk is cheap, show me the code

最近在写一个音乐电台应用,采用服务端、客户端的方式实现。在服务端,用户可以指定一个路径,程序根据这个路径生成播放列表。

需求

服务器是一个一旦开起来就不会轻易关闭的程序,我希望播放列表能够自动刷新。这样当用户添加或删除了某首音乐后不用重启服务器就可以反映变化。考虑到易用性,应该支持由路径直接生成播放列表。歌曲是有封面等其他信息的,要满足这些信息的可定制化,程序也支持由配置文件指定的播放列表。

记一次愉(dan)快(teng)的捉虫

废话

BUG是任何软件都会遇到的问题。它通常是开发人员考虑问题不全面而埋下的隐形炸弹,在条件合适的时候就会爆炸;开发自己埋BUG往往比较容易除错,因为代码都是自己写的,定位问题后git blame一下就可以甩锅了;而程序依赖项里的BUG则排查起来则让人一筹莫展,尤其是在没有足够多信息的情况。

面对来自客户和QA的压力,绞尽脑汁仍无法定位问题开发们只能找借口了🤣

  • It’s a feature,not a bug.
  • That’s the design decision, so not a bug

我以前也遇到框架出问题的情况,不过都是自己改代码改出来的,倒也不是很难排查。但这次挖出来的BUG就完全不一样了

闭包,变量捕获与重入问题

问题描述

公司的APP,在断网后进行一个10秒的倒计时操作,每秒钟都会尝试重新联网。当秒数到0时又重新开始计时,倒计时在用户退出程序或者连上网络结束。

按理说是个很简单的Case。QA却报过来个BUG,说APP状态由

联网->断网->联网->断网

变化后,倒计时的秒数变为

9 3 8 2 7 1

变得不连续了。