C# FAQ:关于泛型

(本文来自Microsoft C# Team的FAQ Blog。我会尽量跟踪这个站点,并不断增补内容。)


Q: C#泛型与C++ templates相比如何?


A: 这个问题相当复杂。


Anders曾在一篇访问中提到这个话题。


需要说明的是,泛型和templates的目的并不一样。有些工作templates做起来比泛型好,反之亦然。


模型(Model)


C++ templates使用编译时模型。当在C++程序中使用templates时,如同有一个微宏处理器在起作用一般。


C#泛型不只是编译器的一个特性,也是运行时环境的特性。类似List<T>这样的泛型类型,在编译后仍保有其泛型特质。换言之,C++编译器的替换工作,在C#泛型世界中是由JIT完成的。


错误检查


通过例子能最好地说明。考虑一个template,其中包括方法如下:


T Add(T t1, Tt2)
{
    return t1 + t2;
}


C++编译器能正确解析此方法。当template被真正地调用时,“T”会被真实类型所替代。设若使用的是int类型,则编译器能正确创建Add方法,因为它明白两个整数如何相加。


但如果使用类似“Employee”这样的类型,编译器将出错,因为它不了解如何相加两个“雇员”。


泛型则不然。因为在编译时并不知道具体类型,所以必须通过泛型类的方式来让编译器了解类型的额外信息。


这通过约束(constraints)来实现。Contraints允许作者规定泛型类型支持的数据类型。


例如:


Class List<T> where T:IComparable


意味着无论何时使用T,都可以往CompareTo()函数中传入T并调用该函数。


约束能提供与templates几乎相当的灵活性,但需要很复杂的约束语法。对于Whidbey,约束只能规定某些操作。


例如,无法约定泛型类型必须拥有一个add操作符,所以不能在泛型类中写“a+b”。


可以在运行时使用反射来实现,但实现上味道不清爽,也会带来性能损失。在未来版本中也许会解决这个问题。


运行时操作


C#泛型拥有完全的运行时支持。你可以在泛型类型上执行反射,在运行时创建泛型类型。在C++中没有同等功能。


空间使用


C++和C#对空间的使用不一样。C++ templates在编译时完成,每种类型都会在编译代码中占用独立空间。


在C#中,对特定类型的实现在运行时创建。当运行时环境创建类似List<int>这样的类型,JIT将查看是否之前创建过这种类型。如果已创建过,将直接使用创建了的代码。如果没有创建过,将获取编译器创建的IL代码,用真实类型进行替换。


其实这并不完全正确。对于每种值类型,都会有单独的本地代码路径。引用类型可以互相分享其实现。


所以,C#泛型占用较少磁盘空间和内存空间,比C++ Template有优势。


实际上,C++ 连接器有一种名为“template folding”的特性。C++连接器寻找同样的本地代码段,如果找到,则把它们放到同一目录。


Template元编程


C++ templates有时用于template元编程(metaprogramming)。C#中没有这种特性。


[作者:Eric Gunnerson]

测试客户端发贴

测试一下客户端发贴。如果没有问题,明天就加入其它细节功能和效果


分段

.Text简单客户端几近完成

可是服务器终端连接不上了……暂时无法使用。:-(

设置TextBox的PasswordChar属性

if (ckbShowPassword.Checked){
  tbPassword.PasswordChar='\0'; 
}
else{
  tbPassword.PasswordChar='*';
}

用tbPassword.PasswordChar=’ ‘;是不行的。其实char类型的初始值就是’\0’,在这里不过是还其本来面目罢了。

一篇有意思的文章

先来看看效果吧——

文章地址:http://www.codeproject.net/cs/miscctrl/flagseditor.asp

.Text简单客户端:架构草案

设置部分:设置WebService URL、UserName、Password。Password应该做加密。暂时不支持Proxy。目前本地Username/Password和远端一样,但在后台应预留未来扩展空间。现在只支持单个blog。

本地登录成功后,自动登录远端WebService,获取相应的Blog信息、Category信息。具体流程:

Login Locally->Login WebService->Get Blog Infomation DataSet->Get Category List DataSet->Display post interface

显示发贴界面。

发贴,成功后给一个信息,清理发贴界面。

明天下午不上班,应该可以做出一个雏形来了。

.Text简单客户端进度

基本完成WebService部分。明天做客户端部分。比较烦人的是如果用.NET做,则客户端机器必须安装有.NET Framework SDK。不过想到这东西也就是自己用,就无所谓了。嘿嘿。

今天来学院的专家是北大外语学院院长刘曙雄教授。虽然出了一点小问题(笔记本电脑插了个没开的电源),后来还是比较顺利地进行了整个过程。

也许月半说得对,我追求的尽善尽美,真的别人不会在意。但是,如果只有别人在意的事才去做的话,人活得会不会太累呢?

.Text简单客户端设想

.Text支持用metaBlogAPI或者WebService做客户端。不过前者只有英文版软件可用(如wBloggar),而且似乎不大灵光,后者则太过简单,连Category都不支持。所以打算自己做一个简单的、第一版只支持新增Post的客户端。大体结构如下——

                            DATABASE
                               |
              .TEXT STORED PROCEDURE
    (我的意思是.Text提供的SQL Server过程)
                               |
                            WebService
                               |
                              Client

在看.Text原来的Stored Procedure时,想起来作者没有提供详细的文档,只能自己研究了。通过查阅源码和数据库结构,大体了解了两个关键存储过程和表中参数的用法。下面简单列一下,备考。

首先,每个Post的CategoryId是放在blog_links表中。这个让我比较迷惑。作者把Post的category当作和“链接”一样的东西,混杂不清。

所以,在添加Post的时候,要执行两个过程:blog_InsertEntry和blog_InsertLink,第二个过程需要第一个过程返回的PostId值。来看看着两个过程的参数意思——

Create Proc blog_InsertEntry
(
@Active bit, //是否publish出来
@Title nvarchar(255), //标题
@TitleUrl nvarchar(255), //标题URL。这个我不大明白,从来没用过。
@Text ntext, //内容
@SourceUrl nvarchar(200), //来源URL
@PostType int, //BlogPost-1, Story-2, Comment-3, PingTrack-4,Undeclared-5,这里用1就好
@Author nvarchar(50), //作者
@Email nvarchar(50), //邮件地址
@SourceName nvarchar(200), //来源
@Description nvarchar(500), //描述,基本没什么用
@BlogID int, //不用解释了吧
@DateAdded datetime, //日期,用当前日期可也
@IsXHTML bit, //1-支持HTML, 0-不支持,对于Post应该支持,Comment则不支持
@ParentID int, //Post为-1, Comment是PostId
@ID int output) //返回ID
……

Create Proc blog_InsertLink
(
@Title nvarchar(150), //标题,对于Post,用Null
@Url nvarchar(255), //URL,对于Post,用Null
@Rss nvarchar(255), //RSS,对于Post,用Null
@Active bit, //活动,1
@NewWindow bit, //新窗口,0
@CategoryID int, //这个关键,不过无需解释了
@PostID int, //同上
@BlogID int, //同上
@LinkID int output //返回ID
)……

这样一来就清楚啦。稍候把发文流程思路整理一下再放上来。

资源库系统

前两天开始写东方研究资源库的东西,感觉不错。特别是用Microsoft Application Block来做数据库访问,方便极了。我自己写了一个连接字符串访问方法,这下更方便啦。

打算这个星期之内完成。预计要注意的地方:

1、资源文件的上传下载管理。现在的想法是把二进制内容放在数据库,不过大尺寸的文件怎么办呢?是否应该放在硬盘目录中?再考虑。

2、缩略图。是否应该生成缩略图?对于图片当然这样会比较好,但是就复杂一些了。

听力教学项目重构

从昨天开始用ASP.NET重构之前用Delphi做的听力远程教学系统,目前为止进度一般。今天完成了基于页面的权限控制和用户登录部分。根据项目需求,没有做成完整的权限控制,仅简单在页面上放置一个自定义的权限检查控件,根据用户角色决定是否让访问。如果权限不对就回到访问来源页。部分代码——

 public class PageAccessControl : System.Web.UI.UserControl
 {
  private void Page_Load(object sender, System.EventArgs e)
  {   
   String clientRole=Session.Contents["UserType"].ToString();
   if (!IsInAccessRoles(clientRole)){
    
    Response.Redirect(Request.UrlReferrer.ToString(),true);
   }
  }
  
  private String accessRoles;
  public String AccessRoles{
   get{ return accessRoles; }
   set{ accessRoles=value; }
  }
  private bool IsInAccessRoles(String Role){
   foreach(String accessRole in AccessRoles.Split(new char[] {','})){
    if (Role==accessRole){ return true; }
   }
   return false;   
  }