C#的强类型解释
一直说C#是强类型语言 通俗地讲 便是指C#中的 变量 在开发时的类型便是明确的 String便是String Int 就是Int 毫无争议 强类型的好处有很多 张嘴便可随意举上几例
能够享受代码提示功能
能够获得重构工具的支持
能够在编译期发现更多错误
……
不过C#也不是 绝对 的强类型语言 因为它也有弱类型 那就是Object 我们知道Object是所有类型的最终基类 任何类型的对象都可以使用Object来引用 可是一旦转化成Object的变量之后 代码提示便消失了 即使我们 明确 对象的确切类型 也必须通过Cast才能使用——更何况它形成了一种被 滥用 或 误用 的机会 例如一段错误代码可能会传入一个不符合约定类型的对象 那么就会造成错误 更严重的是 这样的错误可能只要在 运行时 才能被发现 编译器对此无能为力
类似的 实践 其实很多 例如 方法尽可能接受抽象的类型 而返回具体的类型
ASP NET MVC中对于 强类型 一说最典型的方面便是视图 在ASP NET MVC中每种视图(View Partial Layout)都可以选择弱类型和强类型两种 基类 两者的区别便是Model的类型 强类型视图的唯一区别便是其Model属性为范型参数所指定的类型——而弱类型则自然就是Object了 在这里我提出一个 最佳实践 总是使用强类型的视图 并且所有数据都从Model中获取 这么做可能会在一定程度上增加了代码量 因为我们需要为每个视图建立一个Model 不过我认为这是值得的 在强类型的视图中 VS中能够对Model的各种成员做出丰富的代码提示 我们便可以快速地输入代码 并确保不会出现 拼写 之类的低级错误 如果使用了ViewData这个弱类型的字典 那么每次我们获取某个值之后 都必须将其Cast成具体的类型才能使用 这无疑使视图模板变得复杂而难以维护
其实以上的准则还有另一个层面的内容 使用项目模板安装了ASP NET MVC之后 在~/Views/Shared/LogOnUserControl ascx文件中可以发现对Page User属性的直接访问 这自然可以运行 但是其带来的后果是 弱化 了aspx/ascx/master文件的 模板 概念 而重新让其意识到 我是一张页面 在ASP NET MVC框架中 我们要时刻记着 项目中没有页面 我们始终使用Controller中的Action方法来处理请求 而每个请求需要对应一个磁盘上 物理文件 的思维方式一定需要改变(无论是在用WebForms模型还是MVC模型) 直接访问Page User属性也使我们很难为视图进行独立的单元测试 因为视图与HttpContext直接耦合 而HttpContext的Mock相当困难
在《最佳实践》的示例中 我为每个视图都构建了一个Model 它们都在MyMvcDemo Web UI Models项目中 值得一提的是 由于业务的需要 视图之间很可能出现 数据共享 例如View和Layout(更ASP NET的说法是Page与Master Page)之间共享同一个Model 更进一步 两者之间其实是多对多的关系 如果我们为每个ViewPage定义了强类型的Model 又如何应对同一个ViewPage套用不同ViewMasterPage的情况呢?这个问题最自然的解决方式便是使用接口 一个Model对象不可以有多个父类 但是完全可以实现多个接口 因此 我们往往为强类型的ViewMasterPage指定一个接口作为其泛型参数 从示例中您也可以发现 Site Master的类型为ViewMasterPage<ISiteMasterModel> 而每个ViewPage的Model类型都实现了ISiteMasterModel接口
使用ViewData的另一个坏处是必须使用字符串作为键进行访问 字符串是什么?是常量 分散在各处的常量是维护性的大敌 而使用ViewData则几乎无可避免地将字符串常量分散在控制器和视图两个地方——您可能会觉得 使用枚举不就解决这个问题了吗?如果这么做 相当于为每个视图定义不同的枚举类型 那么我们为什么不直接构造强类型的Model呢?使用字符串作为键的另一个坏处是无法在编译期发现问题 如果您一不小心拼写错误了怎么办呢?您可能会觉得 原本aspx就必须到运行时才会动态编译 不过现在ASP NET MVC的模板已经增加了相关的MSBuild Task 或者使用ASP NET的预编译功能 都可以在编译时对视图进行检查了 这也是我建议大家使用aspx 而不是另一种DSL来构建视图的原因——aspx的周边支持实在是太丰富了
不过在视图中 字符串常量并非只出现在ViewData的访问上 例如 使用ASP NET MVC框架模板创建项目之后 Site Master中生成导航栏链接的代码是这样的
<ul id= menu >
<li><%= Html ActionLink( Home Index Home )%></li>
<li><%= Html ActionLink( About About Home )%></li></ul>
代码使用了Html ActionLink这个辅助方法生成一个导向至某个Action的链接 只可惜这里又出现了字符串参数表示的Controller名和Action名 事实上 如果您下载了ASP NET MVC RC的源代码之后 能够发现其中的MvcFutures项目中包含了 强类型 的ActionLink辅助方法 于是我们的代码就能修改为如下模样(参见《最佳实践》的示例)
<li><%= Html ActionLink<HomeController>(c => c Index() Home ) %></li>
<li><%= Html ActionLink<HomeController>(c => c About() About ) %></li><li><%= Html ActionLink<AccountController>(c => c Register() Register ) %></li><li><%= Html ActionLink<AccountController>(c => c List( ) Admin ) %></li>
这下我们便可以使用Lambda Expression这个强类型的表示方法来 告诉 ActionLink方法究竟该生成导向至哪个Action方法的链接 甚至我们可以在 调用 Action方法的同时指定其参数——例如最后一行代码 指定将查看 第一页 内容 而这些数据在交给URL Routing的配置后便能得到我们想要的URL MvcFutures中还定义了其他类似的辅助方法 例如UrlHelper中的辅助方法则会直接生成一个URL链接——而不是一个元素 可惜目前MvcFutures中的这些辅助方法编写的并不完全 正确 因为它直接把方法名作为Action的名称来使用 而ASP NET MVC从某个预览版开始引入了ActionNameAttribute 可以为一个Action方法指定一个不同的Action名称 因此如果您使用ActionNameAttribute来改变Action名 则很可能您需要构建自己的辅助方法 不过这条准则依旧成立 使用强类型的表示法生成URL地址
如果您要使用MvcFutures中的内容 则必须自行编译MvcFutures项目 有一点值得注意 如果您使用直接编译ASP NET MVC RC解决方案所得到的Microsoft Web Mvc dll 就会发现它依赖的是 System Web Mvc Version= Culture=neutral PublicKeyToken=null 而您开发时所使用的 也就是安装在系统中的程序集是 System Web Mvc Version= Culture=neutral PublicKeyToken= BF AD E 两者不同自然难以兼容 幸运的是 您只要手动修改一下MvcFutures项目的程序集引用就可以了 对您来说这一定不是问题
lishixinzhi/Article/program/net/201311/11411