一起谈.NET技术,由扩展方法引申出的编程思维

简介:   1. Helper大爆炸  .NET Framework为我们提供了丰富的类库,但是这并不是万能地,在大部分的时间,我们都需要为我们的项目特殊定制我们的通用类库。  常常,我们都可以构造一个类,类里封装一些方法。

  1. Helper大爆炸

  .NET Framework为我们提供了丰富的类库,但是这并不是万能地,在大部分的时间,我们都需要为我们的项目特殊定制我们的通用类库。

  常常,我们都可以构造一个类,类里封装一些方法。但是对于很多时候,我们并没有办法提取出这样一个类,举一个小例子,我们在很多时候,需要把url给保存到数据库里,作为一个唯一标识,但是我们知道url所占空间很大,如果用url来建立索引的话是非常耗费空间,而且影响效率的,那么我们最常用的办法就是把url做一个Hash来作为索引的替代品。

  这个时候,我们根本就没有办法说我们来怎么样提取一个类,然后在类里写这样一个方法,这个时候,我们通常就只能这样:

 
 
public static class HashHelper
{
public static string GetHashCode( string s)
{
// GetHashCode........
return String.Empty
}
}

  然后我们会这样使用:

 
 
public static void Main( string [] args)
{
string url = " www.fandongxi.com "
string sql = " insert into Test values(' " + HashHelper.GetHashCode(url) + " ') "
// 执行SQL
}

  这里,只是一个例子,并不是说我们要这个样子拼接字符串。

  很快,肯定又会出现一个情况,说,我们要保存网页的内容,但是网页的内容直接存储到数据库里太大了,那么我们就需要对网页文本做一个Base64的压缩。

  那么,我们就又得继续写:

 
 
public static class Base64Helper
{
public static string GetBase64Text( string text)
{
// Base64........
return String.Empty
}
}

  接下来我们在使用的地方就又多出来一个Base64Helper。那么过几天,还会出现SHA1Helper , MD5Helper等等各种各样的Helper。

  渐渐地,我们会不会发现,Helper的数量已经让我们难以忍受了呢?

  2. 扩展方法的提出

  接下来的事情,我们都知道了,在.NET Framework 3.5中,也就是在C#3.0中,引入了扩展方法这个概念。

  那就让我们扩展方法来解决上面的难题。

  各位现在一定知道,无论是做UrlHashCode,还是Base64压缩,还是SHA1加密,还是MD5加密,这些都是针对字符串,或者说是一段文本的处理,那么很自然地,我们就需要把这些全部写入String类的扩展方法中。

 
 
public static class ExtensionClass
{
public static string GetHashCode( this string s)
{
// ........
}
public static string GetBase64Text( this string text)
{
// .......
}
}

public static void Main( string [] args)
{
string url = " www.fandongxi.com "
string sql = " insert into Test values(' " + url.GetHashCode() + " ') "
// 执行SQL
}

  在这里,我不想剖析去读扩展方法的实现本质,这里我们只谈编程思维和扩展方法所带来的意义。

  3. 扩展方法让C#更加面向对象

  从面向对象的角度来看,世间万物皆为对象,所有属性,所有方法都是属于某一个对象的,那么再从这个角度看开去,本就不应该存在静态类,也不应该存在静态方法,所谓的静态,不过是面向对象语言对并不成熟的语法实现的一种屈从罢了。

  我们要求Base64加密后的文本,其实是文本调用自身的一个方法,之所以我们在之前的方法中需要一个Base64Helper,而不能这样子"http://www.fandongxi.com%22.replace(%22com%22,%22cn/")直接调用,只是因为.NET Framework无法预计到我们所有的业务场景,所以把只能把最通用的方法封装到已有的类库中。

  4. 从扩展方法向外谈一些

  让我们从扩展方法逐渐地向外围来探讨一些关于编码规范,以及一些代码优雅的问题。我们先不妨假设我们并不存在“+”运算符,或者说,我们禁止在程序中使用+运算符,那么也就是说,我们需要对“+”这个操作来做一个简单的封装,那么我们常规意义上会怎么做?

 
 
public int Add( int a, int b)
{
return a + b;
}

public static void Main( string [] args)
{
int result = Add( 3 , 4 )
Console.WriteLine(result)
}

  让我们来看这个函数,我们顺着代码的意思向下读,加,3,4。这明显是不符合我们常规的数学思维的,如果用了扩展方法之后,我们一定是应该这样来写。

 
 
public static class Extension
{
public static int Add( this int a, int b)
{
return a + b;
}
}

public static void Main( string [] args)
{
int a = 3 ;
a.Add(b)
}

  可是这个"."运算符看上去还是那么有点别扭…..没办法,至少这样读上去让我们的代码顺畅了很多不是么?像写文章,说话一样写代码一直是我们程序员追求的最高境界,就像这样的代码总是好的。

  Good:people.eat(food)

  而不是Bad:Eat(people,food)

  对把!

  5. 前缀,中缀和后缀表达式

  说到这,就不得不谈谈前缀,中缀和后缀表达式了。

  学过数据结构的朋友们,一定都记得在数据结构中,有一道经典的习题,就是利用“栈”来实现前缀,中缀和后缀表达式的转换。在考试题中也经常会出现这样的习题。那现在让我们来复习一下,什么是前缀,中缀和后缀表达式。

前缀表达式就是不含括号的算术表达式,而且它是将运算符写在前面,操作数写在后面的表达式,也称为“波兰式”。

  大名鼎鼎的Lisp就是前缀表达式的典型,让我们看一个最简单的小例子,还是那个经典的斐波那契数列:

 
 
(define (fib n)
(fib
- iter 1 0 n))

(defile (fib
- iter a b count)
(
if ( = count 0 )
b
(fib
- iter ( + a b) a ( - count 1 ))))

  每次写Lisp的时候,都会被密密麻麻的括号所吓到,可是真的没什么太好的解决方案呢!

  中缀表达式就很简单了,和我们常规所涉及到的代码是一样的,后缀也是一个道理,在此就不再一一赘述。鉴于后缀的应用不是很大,在此我们也只谈谈前缀和中缀的意义。

  那么我们想想,为什么Lisp要采用这么蹩脚的前缀表达式语法呢?

  记得在大二第一次学习C语言的时候,老师让我们写一个简单的计算器,当时每个同学都写出了+,-,*,/的操作,但是在当时大多数的我们都没有办法写出更为常用的混合运算,以及()的操作,当时只有班上某鹤立鸡群的哥们写出了让我们当时完全无法看懂的代码。再直到大三学习数据结构,再反过来想他当时的代码,才恍然大悟。

  废话说了一堆,那么其实前缀表达式最大的意义就是他更贴近计算机的思维,他只需要两种操作就能完成运算,就是入栈和出栈。让我们来看一个简单的小例子

  3+(1-4),首先这是一个中缀表达式,把他转换为前缀表达式就是+3 – 1 4,计算机会从右向左来扫描这个表达式,4入栈,1入栈,然后遇到 - ,1和4出栈,并且完成运算,(-3)入栈,3进栈,+入栈,(-3)和3出栈,完成运算。

  也就是说,其实在计算机完成我们所编写的数学操作时,其实往往都是把我们的中缀表达式首先转换为前缀表达式,然后完成计算,而Lisp采用前缀表达式,则是省去了这一个步骤,从而提高解释器的效率。

  那我们就来总结下前缀和中缀表达式的意义。

  前缀表达式更加贴近计算机思维,方便计算。而中缀表达式更加贴近数学思维,容易被我们所理解。

  那回顾下,我们之前写Add的代码,如果说我们去掉.运算符,而且方法不加括号,是否采用扩展方法,把C#的语法和Lisp的语法相结合,其实就成了这样的形式。

 
 
public int Add( int a, int b)
{
return a + b;
}
public static void Main( string [] args)
{
(
set ! result (Add a b))
}
public static class Extension
{
public static int Add( this int a, int b)
{
return a + b;
}
}
public static void Main( string [] args)
{
(
set ! result (a Add b))
}

  还是后者更贴近我们的自然思维一些。

  .NET Framework很强大,给我们提供了扩展方法这个概念,那么如果没有了扩展方法,其他语言给出了怎么样的解决方案呢?

  那让我们来看看Haskell给出的方案。

  5. 看看Haskell的方法

  Haskell是一门函数式的语言,在FP大行其道的今天,Haskell这门久居深宫的语言也渐渐地浮出了水面。

  废话不多说,我们只来看看Haskell是如何在没有扩展方法的情况下来解决语法和自然思维不相协调的问题的。

  让我们先来编写一个简单的Haskell函数。

  add x y = x + y

  代码很简单,没什么值得多说,让我们来看看Haskell怎么调用。

image  这是我们传统的调用方式,可是Haskell为了更贴近我们的自然思维,为参数个数数量为2的方法提供了这样一个便捷的调用:

image  这就是Haskell为我们提供的“中缀表达式”的解决方案。

  扩展方法很好,但是当我们的语言中没有扩展方法的时候,Haskell给我们提供了一个优秀的典范。

  6. 语言和类库

  说到这,我就想顺便谈谈关于语言扩展和类库扩展的问题。

  在《Masterminds of Programmming》一书中,Python语言之父Guido在接受采访时,谈到PEP(Python增强处理)时,顺便说到了关于在编写编程语言时,如何来根据用户的意见来处理语言实现的问题。

  他谈到:

如果某个用户提出一个新特性,它几乎不会成功。因为用户对实现没有全面的理解,他几乎不可能提出一个合理的新特性。

  那么在我看来什么是用户?用户就是使用这门语言来完成工作任务的人,他们往往需要的都是增加一个新功能,换句话说,他们需要的仅仅是一个方法而已。

  那么什么是增加语言特性,什么是增加类库方法,Guido也给出了比较合理的解释。

如果某个特性对于Web来说确实很棒,那么,对于加到语言中来说,就未必是优秀的特性了。如果它确实利于编写更短的函数,或者是有利于编写可维护更强的类,把它添加到语言中可能就是一件好事。

  其实Guido的意思很简单,是否增加到语言中,关于在于这个特性是否是领域相关的,如果是领域相关的,也许它需要做的仅仅是扩展类库,无论是增加Python的类库,还是用C去扩展Python API,总之无需对语言做出改变。

  那么对于C#来说,什么是类库的修改,什么是语言的修改,在我看来,每一个版本的修改都一定有着类库的修改,但是如果说到语言的修改,应该是仅仅当MSIL发生变动的时候,我们才可以说语言发生了修改。//仔细想了一下,这个观点有问题....但是我没找到更合适的语言来做比喻。也许应该说,只有当语法的编译规则发生改变的时候,我们才可以说语言发生了修改。

  Python也是一样,增加了方法充其量是类库的修改,而仅仅是语言的解释过程都发生了修改才可以算得上是语言层面的修改,例如从Python 2.x到Python3.x的大版本变动。

  7. 总结

  在本文中,主要是从扩展方法说起,谈到我们该怎么样更好的编写更贴近自然语言的程序。

  然后再到一些没有扩展方法语言给出的折衷实现。而对于Python,C等其他语言,我尚且没有找到合适的方法来解决问题。

  如果各位有好的办法,尤其是对于Python,毕竟这是我的工作,希望各位补充给出解决方法。

  谢谢。

目录
相关文章
|
8天前
|
人工智能 开发框架 量子技术
【专栏】.NET 技术:驱动创新的力量
【4月更文挑战第29天】.NET技术,作为微软的开发框架,以其跨平台、开源和语言多样性驱动软件创新。它在云计算、AI/ML、混合现实等领域发挥关键作用,通过Azure、ML.NET等工具促进新兴技术发展。未来,.NET将涉足量子计算、微服务和无服务器计算,持续拓宽软件开发边界,成为创新的重要推动力。掌握.NET技术,对于开发者而言,意味着握有开启创新的钥匙。
|
8天前
|
开发框架 .NET C#
【专栏】理解.NET 技术,提升开发水平
【4月更文挑战第29天】本文介绍了.NET技术的核心概念和应用,包括其跨平台能力、性能优化、现代编程语言支持及Web开发等特性。文章强调了深入学习.NET技术、关注社区动态、实践经验及学习现代编程理念对提升开发水平的重要性。通过这些,开发者能更好地利用.NET构建高效、可维护的多平台应用。
|
8天前
|
机器学习/深度学习 vr&ar 开发者
【专栏】.NET 技术:引领开发新方向
【4月更文挑战第29天】本文探讨了.NET技术如何引领软件开发新方向,主要体现在三方面:1) 作为跨平台开发的先锋,.NET Core支持多操作系统和移动设备,借助.NET MAUI创建统一UI,适应物联网需求;2) 提升性能和开发者生产力,采用先进技术和优化策略,同时更新C#语言特性,提高代码效率和可维护性;3) 支持现代化应用架构,包括微服务、容器化,集成Kubernetes和ASP.NET Core,保障安全性。此外,.NET还不断探索AI、ML和AR/VR技术,为软件开发带来更多创新可能。
|
8天前
|
开发框架 Cloud Native 开发者
【专栏】剖析.NET 技术的核心竞争力
【4月更文挑战第29天】本文探讨了.NET框架在软件开发中的核心竞争力:1) .NET Core实现跨平台与云原生技术的融合,支持多操作系统和容器化;2) 提升性能和开发者生产力,采用JIT、AOT优化,提供C#新特性和Roslyn编译器平台;3) 支持现代化应用架构,包括微服务和容器化,内置安全机制;4) 丰富的生态系统和社区支持,拥有庞大的开发者社区和微软的持续投入。这些优势使.NET在竞争激烈的市场中保持领先地位。
|
8天前
|
开发框架 .NET 开发者
【专栏】领略.NET 技术的创新力量
【4月更文挑战第29天】.NET技术自ASP.NET起历经创新,现以.NET Core为核心,展现跨平台能力,提升性能与生产力,支持现代化应用架构。.NET Core使开发者能用同一代码库在不同操作系统上构建应用,扩展至移动和物联网领域。性能提升,C#新特性简化编程,Roslyn编译器优化代码。拥抱微服务、容器化,内置安全机制,支持OAuth等标准。未来.NET 6将引入更快性能、Hot Reload等功能,预示着.NET将持续引领软件开发潮流,为开发者创造更多机会。
|
8天前
|
物联网 vr&ar 开发者
【专栏】.NET 技术:为开发注入活力
【4月更文挑战第29天】本文探讨了.NET技术的创新,主要体现在三个方面:1) .NET Core实现跨平台开发革命,支持多种操作系统和硬件,如.NET MAUI用于多平台UI;2) 性能提升与生产力飞跃,C#新特性简化编程,JIT和AOT优化提升性能,Roslyn提供代码分析工具;3) 引领现代化应用架构,支持微服务、容器化,内置安全机制。未来,.NET 7将带来更多新特性和前沿技术整合,如量子计算、AI,持续推动软件开发创新。开发者掌握.NET技术将赢得竞争优势。
|
8天前
|
人工智能 前端开发 Cloud Native
【专栏】洞察.NET 技术的开发趋势
【4月更文挑战第29天】本文探讨了.NET技术的三大发展趋势:1) 跨平台与云原生技术融合,通过.NET Core支持轻量级、高性能应用,适应云计算和微服务;2) 人工智能与机器学习的集成,如ML.NET框架,使开发者能用C#构建AI模型;3) 引入现代化前端开发技术,如Blazor,实现前后端一致性。随着.NET 8等新版本的发布,期待更多创新技术如量子计算、AR/VR的融合,.NET将持续推动软件开发的创新与进步。
|
8天前
|
人工智能 前端开发 Devops
【专栏】洞察.NET 技术在现代开发中的作用
【4月更文挑战第29天】本文探讨了.NET技术在现代软件开发中的核心价值、应用及挑战。.NET提供语言统一性与多样性,强大的Visual Studio工具,丰富的类库,跨平台能力及活跃的开发者社区。实际应用包括企业级应用、Web、移动、云服务和游戏开发。未来面临性能优化、容器化、AI集成等挑战,需持续创新。开发者应深入理解.NET,把握技术趋势,参与社区,共创美好未来。
|
8天前
|
开发工具 C# 开发者
【专栏】理解.NET 技术,开创美好未来
【4月更文挑战第29天】本文探讨了.NET技术在软件开发中的关键作用,强调其核心优势,如语言多样性、丰富类库、强大的开发工具和跨平台能力。.NET在现代应用开发中涉及企业级应用、云服务集成、微服务、移动应用和游戏开发。未来,.NET将持续创新,提升性能,拓展应用场景,并促进更紧密的社区合作,通过跨平台框架扩大应用范围。开发者应深入学习.NET,抓住技术趋势,共创美好未来。
|
8天前
|
机器学习/深度学习 人工智能 开发者
【专栏】.NET 技术:为开发带来新机遇
【4月更文挑战第29天】本文探讨了.NET技术如何为软件开发带来新机遇,分为三个部分:首先,.NET的跨平台革命,包括.NET Core的兴起、Xamarin与.NET MAUI的移动应用开发、开源社区的推动及性能优化;其次,介绍了云服务与微服务架构的集成,如Azure云服务、微服务支持、DevOps与CI/CD,以及Docker容器化;最后,讨论了AI与机器学习集成,如ML.NET、认知服务、TensorFlow和ONNX,使开发者能构建智能应用。面对这些机遇,开发者应不断学习和适应新技术,以创造更多价值。