Joycode@Ab110.com

June 2007 - Posts

Windows Vista Tip (01) : 快速切换日历

本系列归类在“细节”,都是经过实践证明受人欢迎却多人未知的点点滴滴。应该适用于Windows Vista的所有版本,虽然只在英文版的Business和Ultimate下得到确认。

在Windows Vista下显示日历和时间,只要单击任务条上的时间(在Windows XP下则是双击)。这个大家都知道,也不是本Tip所在。

今天是2007年6月30日,加入您想查看2012年2月12日是星期几,会如何操作呢?可以这样

  1. 单击月份(比如June 2007),这时您看到了2007年12个月的视图;
  2. 单击2007,看到2000-2009年的视图;
  3. 您还可以继续单击2000-2009以得到2000-2099的视图。当然因为2010-2019就在2000-2009之后,我们不妨单击右箭头。
  4. (以下步骤省略39字)
  5. 最后看到2012年2月12日是星期六。

单击最上方的日期可以立刻回到最初的视图。

And that is that. The end.

Announcing Windows Live Folders

Get your free 500MB here: http://folders.live.com

 

 

And let us know what you think

用Excel2007与SharePoint列表进行双向同步!

我们都知道,Excel2003是可以非常方便的与SharePoint列表进行双向同步,而到了2007版本,这个功能被取消并移植到了Access2007上。就在上周末的课程上,我还在对学员们讲,这个同步功能要到Access里面做了,而我刚刚发现微软已经发布了弥补这个功能的插件!

http://msdn2.microsoft.com/en-us/library/bb462636(office.11).aspx

这个文档描述了如何将Excel表直接发布到SharePoint网站上,或者如何将修改同步到SharePoint网站上。

点击这里下载此插件

我试用过了,让人十分兴奋!Excel2003的用户可以放心的升级了。

安装后,Ribbon中将出现这个按钮,点击可以将当前的列表发布到SharePoint网站上:

image

如果需要同步的话,就在当前的表格中点右键,选择“表格”-->“与SharePoint列表同步”

image

还不快去下载试试!

MOSS2007应用管理培训圆满结束

上周末,我们度过了非常紧张的三天,通向分享MOSS2007培训的应用管理部分圆满结束。

感谢所有来参加的学员,感谢我的两位助理,也感谢杜伟的不辞辛苦。

本周末(6月30日和7月1日),MOSS2007的开发培训将隆重开始,届时,资深SharePoint开发大牛杜伟老师将全面介绍SharePoint的开发框架和实践经验,当然,还会有丰富的动手实验。

课程还有非常有限的几个空位,需要的话赶快报名,周六周日两天,价格2000元/人。

联系方式:

http://www.colladec.com/class.aspx

或发送邮件到:training@colladec.com

内容丰富的讲义:

DSC07700

CsvParser in C#

前些天正好需要处理一些csv文件(就是逗号分隔文件,常用excel的应该很熟悉),于是想早早.NET里是不是已经有这样的类库了。最后还真的发现了一个。不过有趣的是那个类(Microsoft.VisualBasic.FileIO.TextFieldParser)只有VB.NET的版本。

不过我们是在.NET平台上么,CLR的好处不是只拿来吹吹的。VB.NET写的类,在C#程序里一样能用:

1. 首先Add Refenece(Microsoft.VisualBasic):

2. 然后声明使用的namespace:

using Microsoft.VisualBasic;

3. 接着就可以写代码了, 我加了一些很简单的Schema的功能:

 

using Microsoft.VisualBasic.FileIO; using System; using System.Collections; using System.Collections.Generic; using System.IO; namespace MS.Live.Cumulus.Autopilot.Watchdog { public class CsvParser { /* fields */ TextFieldParser csvParser = null; Dictionary<string, int> textSchema = null; /* methods */ public CsvParser(string inputFile) { csvParser = new TextFieldParser(inputFile); csvParser.TextFieldType = FieldType.Delimited; csvParser.Delimiters = new string[] { "," }; } public CsvParser(Stream inputStream) { csvParser = new TextFieldParser(inputStream); csvParser.TextFieldType = FieldType.Delimited; csvParser.Delimiters = new string[] { "," }; } public void SetSchema(string[] schema) { textSchema = new Dictionary<string, int>(schema.Length); int index = 0; foreach (string field in schema) textSchema.Add(field, index++); // may throw an exception if duplicated field names exist in schema } public string ReadLineRaw() { return csvParser.ReadLine(); } public string[] ReadLine() { return csvParser.ReadFields(); } public string[] ReadFields(string[] filter) { if (null == textSchema) throw new Exception("The parser has no schema defined."); string[] allFields = ReadLine(); string[] result = new string[filter.Length]; for (int i = 0; filter.Length > i; i++) resultIdea = allFields[textSchema[filterIdea]]; return result; } /* properties */ public bool IsEndOfData { get { return csvParser.EndOfData; } } }

4. 最后测试一下:

 

public void TestCsvParser() { CsvParser parser = new CsvParser("input.csv"); try { parser.ReadFields(new string[] { "Address" }); Assert.Fail("This line should not be reached"); } catch (Exception) { } parser.SetSchema(new string[]{ "Name", "PhoneNumber", "Address" }); string[] row = parser.ReadLine(); Assert.IsTrue("FakeID1" == row[0] && "FakePhoneNumber1" == row[1] && "FakeAddress1" == row[2]); Assert.IsTrue("FakeID2,FakePhoneNumber2,FakeAddress2" == parser.ReadLineRaw()); row = parser.ReadFields(new string[]{ "Address", "Name" }); Assert.IsTrue(2 == row.Length && "FakeAddress3" == row[0] && "FakeID3" == row[1]); row = parser.ReadFields(new string[]{ "Name", "PhoneNumber", "Address" }); row = parser.ReadFields(new string[]{ "Name", "PhoneNumber", "Address" }); Assert.IsTrue(3 == row.Length && "FakeID5" == row[0] && "hello,Fake\"PhoneNumber5" == row[1] && "FakeAddress5" == row[2]); Assert.IsTrue(true == parser.IsEndOfData); }

 

测试的输入文件如下:

FakeID1,FakePhoneNumber1,FakeAddress1
FakeID2,FakePhoneNumber2,FakeAddress2
FakeID3 , FakePhoneNumber3,FakeAddress3

FakeID4, FakePhoneNumber4 ,FakeAddress4
FakeID5, "hello,Fake""PhoneNumber5", FakeAddress5

对于Office Open XML文档格式,请发表您的看法

相信博客堂的读者大部分都对Office 2007新引入的Open XML文档格式有相当的了解了(如果不了解,可以阅读这篇文章:介绍 Microsoft Office (2007) Open XML 文件格式),现在,Open XML文档格式已经是一项ECMA(欧洲计算机制造商协会)标准,同时,微软正在将它提交给ISO国际标准组织。

在ISO组织进行正式投票之前,微软希望能够听到您的看法,得到您的证言。请访问这里:http://www.msotec.net/Lists/Open%20XML%20File%20Format/NewForm.aspx

MySpace招聘SQL专家

MySpace招聘SQL专家,待遇超过Microsoft China,GTSC更加不在话下:p
如果您认为在下述方面有专长,请积极报名:  

1、工作地点:北京;
2、需要有VLDB或高并发数据库实战经验;
3、熟悉Microsoft SQLServer Database engine,了解Index, Lock等
4、有简单的英文沟通能力(至少技术方面要能够交流),可以去美国出差,最好会开车,在美国不会开车很不方便,而我就不会:'(
5、熟悉Replication优先
6、熟悉SSIS优先

请把个人简历发给我:klu@myspace.com

欢迎GTSC SQL Team的兄弟姐妹们跳槽:)

在MySpace,你可以接触到最大的互联网数据库之一。我们有超过200台SQL Server服务器,用户数超过160M。有竞争力的待遇,有挑战性的工作,MySpace.CN期待你的加入!

周末休闲 | 看微软(1):08又有新景点

有句话常被人挂在嘴边:有道是“山不在高,有仙则名。水不在深,有龙则灵”。那是自然。

那些没有仙和龙的地方,要想在5/1黄金周吸引游客,可能就必须要突出山之高和水之深。如果在山高水深的排名榜上位居前列,也就会有游客提篮春光看山水。

人造的体育馆,购物中心,摩天大厦,若是够大够高,本身就成了一景。

微软正在总部修建美国最大的地下停车场之一,不知是否会成为景点呢?因为是地下停车场,所以现在正在挖很巨大的一个坑。最后建成有四层(这在微软不算多,我现在工作这个楼就有四层地下停车场),能容纳5000辆车(这个数字较大)。因此每一层面积约有6个城市的街区。

其实这个项目还不止是停车场,这将成为微软园区的中心。基于此,来微软一游的人,也许真的一定要来到这个停车场里面呢。也许能有与最早园区的不同氛围。

详情请看Seattle Times的报道建成在2008年中。

微软在武汉/长沙/合肥招聘 Account Technology Specialist

[介绍个好职位给大家,该贴暂时放一段时间]

微软公司武汉办事处由于业务的迅猛发展,需要大量人才加盟。
Account Technology Specialist(以下简称:ATS)是微软Sales & Marketing部门最具有活力的职位之一,如果您认为在下述方面有专长,请积极报名:

1、 工作地点:中国湖北省武汉市、湖南长沙、安徽合肥(请慎重考虑);

2、 很强的客户沟通能力和业务拓展能力;很强的微软技术背景和解决方案熟悉度;

3、 理解复杂的客户需求,引导客户技术发展方向,实现客户的商业目标

4、 熟悉Active Directory体系架构和部署方式、熟悉Windows Server 2003主要产品特性和企业部署能力;

5、 熟悉Exchange、SMS、MOM、ISA、Sharepoint等技术和解决方案,如果有上述产品开发部署经验将优先考虑;

6、 熟悉.NET开发,如果有Visual Studio 2005或.NET 2.0/3.0开发经验将优先考虑。

7、至少3年相关工作经验。

有意者可以发送简历到jamesgao@microsoft.com

使用VS2005的 ClickOnce 技术实现按需下载组件

默认情况下,首次运行 ClickOnce 应用程序时,会下载该应用程序中包含的所有程序集。但是一些特殊的场景我们可能不希望它这么干,而是希望按照一定规测或者需要用到某个组件的时候再下载。

比如我们可能会有下面一些应用场景的需求:

1、我开发的这个客户端程序是要收费的。但是免费用户也可以使用部分功能。我在技术实现上把收费用户使用的功能封装到了A.dll 组件了,我希望免费用户根本无法获得A.dll,只有收费用户才能获得A.dll,并加载A.dll中的收费功能。

2、我整个应用程序非常大,我不希望我每次更新,用户都需要把所有应用程序都下载下来,用户应该只需要下载他用到的功能组件。

 

下面我们就来实现一个简单的按需下载的例子,我们完全可以在这个例子基础上,实现上述提到的应用场景1。

演示步骤:

一、新建一个 类库 Project

定义类库输出应用程序名为:OnDemandAssembly,即这个类库编译后产生的文件名为 OnDemandAssembly.dll

这个类库中有如下代码,我们用这段代码来模拟上面提到场景中的一些需要按需加载的功能或者是收费的功能,我们将在主程序中调用这个功能:

using System;

namespace OnDemandAssembly
{
    public class DynamicClass
    {
        public string Message
        {
            get
            {
                return "郭红俊测试ClickOnce按需加载功能。";
            }
        }

    }
}

 

二、新建一个 Window 应用程序

我们将在这个Window 应用程序中加载上述类库。

 

为了便于我们演示这个程序,请确保这个Window程序具备以下功能:

1、有一个 textbox 控件,这个控件在 Window 的OnLoad 事件中,把应用程序的目录显示在这里,方便我们去监控是否上述 OnDemandAssembly.dll 组件被加载了。

代码如下:

private void Form1_Load(object sender, EventArgs e)
{
    this.textBox1.Text = Application.StartupPath;
}

2、由一个  Button  按钮,点击这个按钮后,我们把 OnDemandAssembly.dll 组件中的 Message 信息显示出来,代码如下:

private void button1_Click(object sender, EventArgs e)
{
    DynamicClass o = new DynamicClass();
    MessageBox.Show(o.Message);
}

 

Window程序关于ClickOnce设置比较特殊的地方:

我们来配置ClickOnce发布的一些特殊参数,确保可以按需下载需要的组件

本文中没有详细描述ClickOnce设置的各个步骤和参数,如果你对ClickOnce不是很熟悉,建议你首先看一些ClickOnce的入门文章再来看本文。

比如:http://blog.oracle.com.cn/155011/viewspace_3603.html 这里提供的ClickOnce 文章(这里是提供了一个word压缩文件下载,文章在压缩的Word文件中)

 

选择我们的Window程序,在右键菜单中选择属性,在属性页中选择发布(Publish)标签页。

然后点击 Application File 按钮,我们来设置,需要发布的文件。如下图:

VS2005发布设置中,选择需要发布那些文件的按钮位置

 

上述按钮打开的窗口如下:

我们在打开的窗口中,设置 OnDemandAssembly.dll 文件的 发布状态为 Include,

并在 Download Group 中为OnDemandAssembly.dll 文件新建的一个下载组,我们这里把这个新的下载组命名为 DemandAssembly01 。

说明:

默认情况下,我们用ClickOnce 第一次安装,或者升级程序的时候,系统只下载 Required 组的文件,其他组的文件系统不下载,需要我们自己编码来下载。

 

 

其他ClickOnce的设置跟我们平常使用的时候一样来设置。本文忽略这部分。

 

我们这时候发布这个程序,我们下载安装后,就会发现OnDemandAssembly.dll 文件不在安装目录下,点击这个程序的按钮,就会报异常,找不到需要的应用程序集

OnDemandAssembly.dll 组件。

 

下面我们来编码实现,如果应用程序找不到 OnDemandAssembly.dll 组件,就从网上下载这个组件的功能

1、窗口的构造函数中增加 AssemblyResolve 事件的处理逻辑

public Form1()
{
    InitializeComponent();

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{

}

说明:AppDomain.AssemblyResolve 事件 在对程序集的解析失败时发生。

 

2、下面我们编码实现 AssemblyResolve  事件的处理逻辑

using System.Reflection;
using System.Deployment.Application;

// 如果我们有多个文件都需要按需下载的话,每个文件影射到那个下载分组,就是这个实体来记录的

Dictionary<String, String> DllMapping = new Dictionary<String, String>();

public Form1()
{
    InitializeComponent();
    DllMapping["OnDemandAssembly"] = "DemandAssembly01";
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    Assembly newAssembly = null;

    // 是 ClickOnce 部署方式
    if (ApplicationDeployment.IsNetworkDeployed)
    {
        ApplicationDeployment deploy = ApplicationDeployment.CurrentDeployment;

        // Get the DLL name from the Name argument.
        string[] nameParts = args.Name.Split(',');
        string dllName = nameParts[0];
        string downloadGroupName = DllMapping[dllName];

       // 下载所需要的文件 
  try
        {
            deploy.DownloadFileGroup(downloadGroupName);
        }
        catch (DeploymentException de)
        {
            MessageBox.Show("Downloading file group failed. Group name: " + downloadGroupName + "; DLL name: " + args.Name);
            throw (de);
        }

  // 加载组件到应用程序集
        // Load the assembly.
        // Assembly.Load() doesn't work here, as the previous failure to load the assembly
        // is cached by the CLR. LoadFrom() is not recommended. Use LoadFile() instead.
        try
        {
            newAssembly = Assembly.LoadFile(Application.StartupPath + @"\" + dllName + ".dll");
        }
        catch (Exception e)
        {
            throw (e);
        }
    }
    else
    {
        //Major error - not running under ClickOnce, but missing assembly. Don't know how to recover.
        throw (new Exception("Cannot load assemblies dynamically - application is not deployed using ClickOnce."));
    }

    return (newAssembly);
}

 

一些问题说明:

Q:上述代码中,如果我们这个组件OnDemandAssembly.dll 有最新版本了,并且发布了,但是客户端还是一个老的版本的话,这个逻辑我们没有处理呀?

A:问题这个问题,就是代表你对 ClickOnce 的原理还是不懂,OnDemandAssembly.dll 有最新版本,那你就必须再重新发布一个版本的ClickOnce代码,这时候发布的版本号就不一样了。客户端下不同版本号的ClickOnce 程序是存在不同目录下的(当然服务器也是一样)。

系统检查到你的新版本程序发布后,会为新的版本号建立目录,这个目录下如果你没有用过OnDemandAssembly.dll 的功能,是不会有OnDemandAssembly.dll 组件的,继而上述问题是可以不用考虑的。

 

参考资料:

MSDN:Downloading Assemblies On Demand with the ClickOnce Deployment API

关于书...

1、《Office SharePoint Server 2007 开发入门指南》在6月底7月初就会上市。
2、电子工业出版社正计划引进MSPress的《Microsoft Office SharePoint Server 2007 Administrator's Companion》(可考虑翻译为《Microsoft Office SharePoint Server 2007 管理员指南》),我也在争取成为此书中文版的译者。

Microsoft Office SharePoint Server 2007 Administrator's Companion

Orcas Beta1 对多个同名扩展方法的处理逻辑

说明:以下测试是基于Orcas Beta1环境的测试,VS2008 正式版发布后,也许会发生变化。

 

如果你对扩展方法不是很熟悉,建议先看我之前的两篇博客:

C#3.0 中的扩展方法 (Extension Methods)

C#3.0 中使用扩展方法来扩展接口

 

如果我们项目中,在不经意期间,出现了重名的扩展方法,这时候编译器会如何处理呢?这就是本文要探讨的问题。

 

先说结论:编译器按照下述三个优先级顺序去寻找到底哪个方法被调用到:

假设,我们是在A 命名空间下,调用 类 B 的 C 方法。 类的 C 方法可能是在 D 命名空间下使用扩展方法扩展实现的。

 

1、类 B 中是否真实存在 C 方法(非扩展方法),如果存在,则调用之,存在时,不考虑是否有扩展,直接进行调用。(这种情况请看我之前的博客:C#3.0 中的扩展方法 (Extension Methods)

 

2、命名空间 A ,是否存在对C方法的扩展,如果存在,则调用这种情况下的扩展;看示例代码二

 

3、调用代码中,除了 命名空间 A,还引用了其他命名空间 D和 F。A命名空间没有对C方法进行扩展,则调用D命名空间下的扩展。

 

特殊情况:

如果 F 和 D 命名空间都对 C 方法进行了扩展,则编译器报错误;看下面的示例代码一

如果 D 和 A命名空间都对 C 方法进行了扩展,则调用 A命名空间下的扩展,编译器不会报错;看示例代码二

 

 

示例代码一:

以下代码会编译时报错:

The call is ambiguous between the following methods or properties: 'ConsoleApplication1.MyClass01.DO(int)' and 'ConsoleApplication2.MyClass02.DO(int)

表明     using ConsoleApplication2;     using ConsoleApplication1;  导致 ConsoleApplication2 和 ConsoleApplication1  命名空间同级,同级搜索出现重名,报错。

namespace ConsoleApplication2
{
    using System;
    static class MyClass02
    {
        internal static void DO(this int i)
        {
            Console.WriteLine(string.Format("ConsoleApplication2.MyClass02.DO {0}", i));
        }
    }
}

namespace ConsoleApplication1
{
    using System;
    static class MyClass01
    {
        public static void DO(this int i)
        {
            Console.WriteLine(string.Format("HongJunGuo.MyClass01.DO {0}", i));
        }
    }
}

namespace HongJunGuo.Test
{
    using System;
    using ConsoleApplication2;
    using ConsoleApplication1;

    class Program
    {
        static void Main(string[] args)
        {
            int w = 9;
            w.DO();
            Console.ReadLine();
        }
    }
}

 

示例代码二

以下代码返回的信息为 HongJunGuo.MyClass01.DO 9, 标明优先找 本命名空间下的扩展方法。

namespace ConsoleApplication2
{
    using System;
    static class MyClass02
    {
        internal static void DO(this int i)
        {
            Console.WriteLine(string.Format("ConsoleApplication2.MyClass02.DO {0}", i));
        }
    }
}

namespace HongJunGuo.Test
{
    using System;
    using ConsoleApplication2;

    static class MyClass01
    {
        public static void DO(this int i)
        {
            Console.WriteLine(string.Format("HongJunGuo.MyClass01.DO {0}", i));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            int w = 9;
            w.DO();
            Console.ReadLine();
        }
    }
}

 

特殊情况:如果出现下面的代码:

编译器并不会报错,返回的信息是 ConsoleApplication2.MyClass02.DO ,

这一个的处理逻辑我一直没想明白,在 VS2008 正式版中,最有可能发生变化的,我想就是这种情况吧。

 

namespace ConsoleApplication2
{
    using System;
    static class MyClass02
    {
        internal static void DO(this int i)
        {
            Console.WriteLine(string.Format("ConsoleApplication2.MyClass02.DO {0}", i));
        }
    }
}

namespace HongJunGuo
{
    using System;
    static class MyClass01
    {
        public static void DO(this int i)
        {
            Console.WriteLine(string.Format("HongJunGuo.MyClass01.DO {0}", i));
        }
    }

}

namespace HongJunGuo.Test
{
    using System;
    using ConsoleApplication2;

    class Program
    {
        static void Main(string[] args)
        {
            int w = 9;
            w.DO();
            Console.ReadLine();
        }
    }
}

C#3.0 中 DLINQ 从数据库获得数据集,XLINQ从XML文件获得数据集的方法

DLINQ和XLINQ的具体查询,更新等操作不是本文讨论重点,本文重点解决如何获取需要查询的数据集。

 

DLINQ 如何链接到数据库?

DLINQ可以访问DataSet,这种情况我们在本文就不考虑了,

本文考虑的是直接用DLINQ访问数据库,我们如果用VS Orcas中的LINQ到SQL的新ORM设计器,VS替我们产生了一些代码,这种情况也不是本文考虑的范围。

本文我们要考虑的事情是:如何自己编码去链接数据库,这样我们才能对DLINQ链接数据库有更深入的了解。

 

下面是一个简单的DLINQ代码:获得 pubs 数据库 authors 表的所有作者的 au_id 信息。

using System;
using System.Linq;
using System.Data.Linq;  // 这个命名空间在单独的组件 System.Data.Linq.dll 中

public class DLinqTest
{
    public static void DoSomeThing()
    {
        // 链接字符串       
        string connectionString = "Data Source=192.168.5.2;Initial Catalog=pubs;Persist Security Info=True;User ID=sa;Password=******";

        // 我们就是通过使用 DataContext  来 DLINQ链接数据库的。
        DataContext db = new DataContext(connectionString);
        Table<Authors> authors = db.GetTable<Authors>();
        var users = from a in authors orderby a.au_id select a;
        foreach (var a in users)
        {
            Console.WriteLine(a.au_id);
        }
    }
}

// 数据库中的表结构影射的实体对象,注意其中的 Attribute.

[Table(Name = "authors")]
public class Authors
{
    [Column(IsPrimaryKey = true)]
    public string au_id { get; set; }
    [Column]
    public string au_lname { get; set; }
    [Column]
    public string au_fname { get; set; }
    [Column]
    public string phone { get; set; }
    [Column]
    public string city { get; set; }
    [Column]
    public string state { get; set; }
    [Column]
    public string zip { get; set; }
    [Column]
    public bool contract { get; set; }
}

DLINQ 链接到数据库的步骤:

1、创建数据表跟实体对应的实体类(字段和元素可以不一一对应),并把这个类标上Table 特性,根数据表字段有关的元素标上Column特性;

2、使用 DataContext 和数据库链接字符串建立跟数据库的链接,然后使用 DataContext  的实例的 GetTable 方法获得对应表影射的实体类。

 

 

XLINQ 访问 XML 文件的方法

 

XLINQ 的例子我们就写稍稍复杂点,通过获得我(蝈蝈俊)博客的RSS,然后把RSS中的链接和标题打印出来:

下面就是这个功能的演示代码:

using System;
using System.Linq;
using System.Xml.Linq;

public class XLINQ
{
    public static void DoSomeThing()
    {
        XElement feed = XElement.Load("http://blog.joycode.com/ghj/Rss.aspx");
        if (feed.Element("channel") == null)
            return;

        var rss = from item in feed.Element("channel").Elements("item")
                  select new
                  {
                      title = item.Element("title").Value,
                      link = item.Element("link").Value
                  };
        foreach (var item in rss)
        {
            Console.WriteLine(item.link);
            Console.WriteLine(item.title);
            Console.WriteLine("*****");
        }
    }
}

XLINQ 加载数据的核心就在于 XElement.Load

另外,上述代码中使用了匿名类型,不知道大家还记不得我前几篇博客设计到的这个知识点。

 

参考资料:

Linq学习笔记(2.1)——初识 DLinq

The LINQ Project

XLinq: Reading RSS and Atom using XLinq

Query Data and Generate an RSS Feed in the same XLinq/DLinq Query!

C# 3.0 的Lambda表达式(Lambda Expressions)

Lambda 表达式(拉姆达表达式) 和 匿名方法 其实是一件事情。唯一的不同是:他们语法表现形式不同。Lambda 表达式是在语法方面的更进一步的进化。在本质上,他们是一件事情。他们的作用都是:产生方法。即:内联方法。

引用自 C#首席架构师Anders Hejlsberg 的原话:

http://www.ondotnet.com/pub/a/dotnet/2005/10/31/interview-with-anders-hejlsberg-part-2.html?page=2 

lambda expressions and anonymous methods are really just two words for the same thing. The only thing that differs is, "What does the syntax look like?" And the lambda expressions are a further evolution of the syntax.But underneath, they do the same thing. They generate methods. You know, they're in-line methods.

 

所以:我们要了解 Lambda 表达式 就应该同时也了解 匿名方法。下面先看一个简单的代码例子,分别用匿名方法和Lambda 表达式来实现对数组的搜索:

 

使用 .net 2.0 的匿名方法来搜索字符串数组中包含 a 的字符串数组

static void Main(string[] args)
{
    string[] list = new string[] { "abc", "12", "java" };
    string[] ll = Array.FindAll(list,
        delegate(string s)
        {
            return s.IndexOf("a") >= 0;
        }
        );
    foreach (string var in ll)
    {
        Console.WriteLine(var);
    }
    Console.ReadLine();
}

 

使用 .net 3.5 的Lambda表达式来搜索字符串数组中包含 a 的字符串数组

static void Main(string[] args)
{
    string[] list = new string[] { "abc", "12", "java" };

    string[] ll = Array.FindAll(list, s => (s.IndexOf("a") >= 0));
    foreach (string var in ll)
    {
        Console.WriteLine(var);
    }
    Console.ReadLine();
}

 

从上述两个例子我们可以看出:

从代码书写角度,代码可读性角度来说:Lambda表达式 比匿名方法更简单了。

而 Lambda表达式 和 匿名方法都是干的同一件事情,让我们少写一个函数定义。函数的调用和函数的实现在一起完成了。

 

Lambda表达式的书写格式如下:

(参数列表) => 表达式或者语句块

其中:

参数个数:可以有多个参数,一个参数,或者无参数。

参数类型:可以隐式或者显式定义。

表达式或者语句块:这部分就是我们平常写函数的实现部分(函数体)。

 

 

一些Lambda表达式的书写范例:

 

有两个参数的 Lambda表达式例子:

注:别看比较复杂,LINQ中实际把 下述代码中的 delegate ,DoSomeThing 替你做了,所以你写代码的时候只需要写

var t = DoSomeThing<int>(7, 8, (x, y) => x * y); 这么一行。


public delegate T HongJunGuoTest01<T>(T t1, T t2);
class Program
{
    private static T DoSomeThing<T>(T t1,T t2,HongJunGuoTest01<T> match)
    {
        return match(t1, t2);
    }

    static void Main(string[] args)
    {
        var t = DoSomeThing<int>(7, 8, (x, y) => x * y);
        Console.WriteLine(t);
        Console.ReadLine();
    }
}

 

下面这些写法也是对的(你只需要修改Main函数中的代码,其他地方不需要动):

var t = DoSomeThing<int>(7, 8, (int x, int y) => x * y);

var t = DoSomeThing<string>("7", "8", ( x,  y) => x + y);

或者我们写一个更复杂的: => 右边是一段语句块。

var t = DoSomeThing<int>(7, 8, (x, y) => { if (x < 5) { return (x + 8) * y; } else { return y; } });

 

最前面的例子是一个参数的例子,我们就不举一个参数的例子了,下面举一个没有参数的例子:

public delegate void HongJunGuoTest02();
class Program
{
    private static void DoSomeThing(HongJunGuoTest02 match)
    {
        match();
    }

    static void Main(string[] args)
    {
        DoSomeThing(() => Console.WriteLine("jajaja"));
        Console.ReadLine();
    }
}

 

函数式编程

匿名方法,Lambda表达式 都是函数式编程思想下的产物,

函数式编程如果从概念角度来理解,比较晦涩,简单来说:

函数式编程的主要特点就是没有变量,所有算法都用递归函数来书写。整个程序除了定义函数就是调用函数,没有其他类型的语句。

这种编程思想的好处和特点,建议参看下面文章:函数式编程另类指南

 

 

参考资料:

Lambda表达式和表达式树(Lambda Expressions and Expression Trees)

C#3.0规范(四)Lambda 表达式

新Orcas语言特性:Lambda表达式

Visual C# 3.0 新特性概览

Linq的超越——强类型反射

Lambda表达式的应用

函数式编程另类指南

已知OO世界中函数式编程实践和小结

C#:昨天,今天和明天:和 Anders Hejlsberg 座谈,第三部分

C# 2.0:使用匿名方法、迭代程序和局部类来创建优雅的代码

移山之道 封面设计 征稿

博客堂中藏龙卧虎,希望有人能帮助我设计《移山之道》的封面。

征稿 - http://yishan.cc/blogs/xin/archive/2007/06/11/483.aspx

谢谢!

More Posts Next page »