c#和TypeScript(javascript)的风格区别

总是要在两者间切换,做一下笔记:

1. 变量和参数的类型,C#是类型在前,变量名在后;TS是变量名在前,类型在后。
2.用花括号表达式new一个对象时,设属性值, C#用等号,TS用冒号。有一点是相同的,不用指定属性类型(c#如果是匿名类对象会自动推导出类型,JS本来就可以根据表达式推导出类型)

3.Optional parameter, c#的函数里的可选参数只能在最后,用等号给出默认值。而TS里分裂出两种,一个是Optional parameter,可选参数,参数名后加问号,也是只能用在最后,不传值的时候就是undefined(不能指定默认值, 简单化为undefined,有点类似nullable, 但是undefined和null是两个类型(值),虽然都可以转成bool类型);另一种是default-initialized parameter, 这种可以指定默认值,用等号给出,不一定要放在最后,如果放在前面的时候希望使用预定义的默认值,必须传undefined来取到(这个设计有点多余,我直接传默认值不就行了,传个undefined还要让别人推测函数定义的参数默认值是什么,而参数默认值就不应该在发布后改变,所谓的灵活没有意义),但如果是放在必须参数的后面,则也是可选的,会变成带默认值的可选参数(和c#一样)。而对于Javascript(最宽松),所有参数都是可选的,不传的时候就是undefined, 从ES6/ES2015起,javascript也支持参数带默认值(等号)。

ConsoleApp中正确等待async方法的写法

这也很重要,因为ConsoleApp不像UI App(Winform/WPF), 它没有SynchronizationContext来Post异步后的代码块,instead, 它是新建一个线程来运行TaskAwaiter里的异步代码块。这种行为和asp.net core一致。而传统asp.net则是有de >AspNetSynchronizationContextde> 的。 参见:https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html

这种没有SynchronizationContext的环境意味着你可以放心大胆地用.Wait(), task.Result等来阻塞task,而不用担心Library中没有ConfigureAwait(false)而引起的死锁。因为Library的异步方法总能从thread pool中找到新的线程来resume执行。

private async static Task GetResult()
{
HttpClient client = new HttpClient();
var task = client.GetAsync(“http://www.google.com”);
var str = await task; //start a new thread to access google.com
var task2 = task.ContinueWith(e =>
{ //start another new thread to resume the execution after http get

System.Threading.Thread.Sleep(10000);
if (e.IsCompleted)
{
Console.WriteLine(str.Content.ReadAsStringAsync().Result);
}
});
Console.WriteLine(“Waiting for the result”);
await task2; //The whole GetResult task consists of two sub-tasks(two steps before completion)
}

static void Main(string[] args)
{
GetResult().Wait(); //Block the main thread before exit, no problem, no deadlock.
Console.ReadKey();
}

SOLID原则

http://www.c-sharpcorner.com/UploadFile/damubetha/solid-principles-in-C-Sharp/

这个印度人写得不错。我来精简一下我的理解:
S:单一责任–这是废话,谁会写ClassForAandB这样的类?在类命名精确的前提下,违反这个原则的代码应该不会出现, 如果非要违反命名,挂羊头卖狗肉,也可以说破坏了关(close to modification)。
O:开关原则–这才是SOLID的基础和精华,写代码都知道要用类的继承封装变化点,这就是开(open to extension)。但是往往容易忽略什么需要关的(close to modification)。从软件开发=代码堆砌的角度看,历史代码能够关上说明其命名精确,实现逻辑稳定,一些类库中几十年前写下而沿用的模块就是成功的关的例子。
L:Liscov是个女人,这个女人也说了一句废话,子类要能够替换父类的工作。对于那种子类的方法完全不做父类方法的工作的做法,本身就是违反方法名的,一定会违反我的命名要精确的前提。违背这个原则也算是违背了close to modification,因为子类modify了父类逻辑(导致不能替换工作),也可以说是没开好(子类本来是父类的extension,但是extend了错误的逻辑)。
I:接口分离原则,大而全的接口是不好的。大接口最好的情况就是实现类的方法里直接return什么也不做地实现接口 ,或者定义一个什么也不干的抽象方法 和抽象类(也算是方法或者类的命名不精确,如果非要定一个AbstractXXX的名,也可以说是一种不好的开的实践,虽然子类也可以算是开放扩展),最坏的情况就是导致违反LSP,例子就是微软的Array类违反了LSP(结果,没关好, Array的IList<T>实现throw exception),直接原因就是没做好Interface Separation。
D: 依赖反转,这是依赖注入的前世吧,首先要破除直接依赖,尽量引入接口。好的代码就是高内聚(High cohesion,也就是开关原则里的关),同时要低耦合(loose coupling,也就是开关原则里的开)。依赖就是耦合,要降低,也就是真正的开好。依赖反转所说的破解依赖的方法就是引入接口,将来的变化点通过类的继承得以扩展(继续堆砌代码,开)。本来存在依赖(没开好)的地方引入了抽象接口之后,变成了开放的可扩展的结构,一下子反转了这种依赖。稍微扩展一些,依赖=>接口化=>便于容器注入实现, 这就是现在流行的依赖注入,把依赖的注入责任从代码中解放出来放到配置里,从而实现了控制权的反转(后期的人可以控制前期固定的代码)。这算是反转进阶吧。
总结:SOLID都和开关原则有关,是开关原则的体现。