[MVC]ASP.NET MVC: Using UserControls Usefully

mikel阅读(788)

转载:http://blog.wekeroad.com/2008/01/07/aspnet-mvc-using-usercontrols-usefully/

This is an interesting issue, and as he went on to point out, there are lots of ways to use these partial UI bits to your advantage. As always, I'll offer some ideas here for you, but this is not the only way to do it.

 

The "Viewlet"
Given that a ViewPage inherits from System.Web.Page, you can still register and reference a UserControl (.ascx file) on a View and have it render. You can even pass it data in the code behind or as a property setting:

<uc1:MyUserControl ID=myControlView runat=server myProperty="Hi Mom" />

But using the WebForms model inside MVC can be a little confusing – especially for folks who will pick up your project later. In this case – the ViewUserControl will render just fine, and in many cases it's all you need. But if you're interesting in keeping things as modular as possible within MVC, read on.

Your UseControl can be one of two things:

  • A granular bit of UI that renders information passed from a Controller
  • A granular bit of UI that renders information from an application-wide data source

The idea here is reusability and maintainability.

I personally don't like the idea of putting logic into ViewUserControls, but at the same time it can serve a purpose – with portal stats for instance where you might want to serve up personalized links (using the Memebership.Profile for instance), etc.

In other MVC frameworks they make a distinction between the two. In Rails, for instance, a "Partial" is simply a View that's shared between views, and not meant to be standalone. If you've ever used Rails to create the demo scaffold, you've used the partial "_form.rhtml" which is responsible for rendering an input form for the New and Edit views.

If you need more than basic rendering of HTML in Rails, you can move to a Layout. Layouts essentially wrap UI around some logic, and are a nice modular way to reuse UI/logic elements around an application. These are like "UserControls Light".

Rails also allows for "sub apps" called "Components", which are useful when you have "sub applications" like an image gallery or rss reader. The idea here is that these components contain their own logic and can be used between many applications.

My point with all this is that if you feel lost trying to make a decision (architecturally) regarding MVC – it helps to see how other platforms do it (like Rails or Django).

 

Rendering a ViewUserControl
The MVC Toolkit has a nice method called "RenderUserControl()" that allows you to process your ViewUserControl and output it's result inline:

 
<%=Html.RenderUserControl(“~/UserControls/UserList.ascx”)%>

If the ViewUserControl is typed (say ViewUserControl<MyControllerData>), then it's ViewData object will be filled for you, and your ViewPage and rendered control will share the same data.

If you want to be explicit about it, you can do that as well, specifying the data to pass:


<%=Html.RenderUserControl(“~/UserControls/UserList.ascx”,ViewData.Users)%>

Finally, if you need to set properties on the ViewUserControl, you can do that as well by passing in an anonymous type:


<%=Html.RenderUserControl(“~/UserControls/UserList.ascx”,ViewData.Users, new {GroupID=2})%>

 

Using the RenderUserControl method allows you to have complete control over how your ViewUserControl is supposed to be used

 

Summary
UserControls are a great way (still) to encapsulate UI elements for your MVC app. There are many ways to use them, and if you have one I didn't mention (or dislike my approach here) – do let me know. As always – we're still CTP and there's lots of room for comments.

[MVC]ASP.NET MVC Tip #14 – 创建模板辅助方法

mikel阅读(859)

[翻译] ASP.NET MVC Tip #14 – 创建模板辅助方法

摘要:在这个Tip中,你将学到在MVC框架中显示数据库数据时,如何创建和使用模板。Stephen Walther介绍了如何创建一个名为RenderTemplate()的辅助方法。

7月4号这个周末,当我回到加利福尼亚的家中后,我和我聪明的哥哥谈起来使用ASP.NET Web Forms、ASP.NET MVC和Ruby on Rails创建Web应用程序的不同。我于是感叹在创建ASP.NET MVC应用程序时,我真的很想念控件。我尤其想念ASP.NET Web Forms控件中的模板带来的HTML与UI逻辑之间的清晰的分离。Repeater控件和for…next循环真的不一样。

我的哥哥告诉我一个很吃惊的东西。他说“模板,Ruby on Rails有模板,他们称之为partials。”最初,我并不理解。我一位Ruby on Rails中的partials或多或少和ASP.NET MVC中的用户控件有点像。然而,我哥哥向我解释了当在Ruby on Rails应用程序中呈现一个partial时,你可以向其传递一组项的集合。集合中的每一项都由partial来呈现。

酷。你可以用同样的方式在ASP.NET MVC应用程序中创建模板。创建一个新的辅助方法,它接受一个IEnumerable和一个用户控件的路径。对于IEnumerable中的每一个元素, 辅助方法都会将用户控件作为一个模板。清单1包含了名为RenderTemplate()的辅助方法。

清单1 – TemplateExtensions.cs

假设你想显示一个电影列表。你可以使用清单2中的HomeController返回一个电影实体的集合。Index()操作执行了一个LINQ to SQL查询,并将查询结果传递给Index视图。

清单2 – HomeController.cs

清单3中的视图简单地调用了RenderTemplate()方法,并肩ViewData.Model和一个包含了每一个电影模板的MVC用户控件的路径传递给该方法。

清单3 – Index.aspx

MovieTemplate.ascx MVC用户控件是强类型的。清单4列出了该用户控件的后台代码。注意用户控件的强类型,使其只能展现Movie实体。

清单4 – MovieTemplate.ascx.cs

最后,清单5给出了MVC用户控件的视图部分。注意你可以使用ViewData.Model.Title和 ViewData.Model.Director这样的表达式来显示电影的标题和导演。这些表达式能够工作是因为你为MVC用户控件使用了强类型,使它只 能展现电影实体。

清单5 – MovieTemplate.ascx

当你请求Index视图时,你将得到图1所示的页面。注意对于每个电影都呈现了一个MVC用户控件。

图1 – 使用模板呈现电影记录

图1 - 使用模板呈现电影记录

小结

在这个Tip中,我介绍了在ASP.NET MVC应用程序中如何创建和使用模板。我演示了如何通过创建MVC用户控件来创建模板,以及如何使用模板来呈现一组数据库记录。今后再也不用在ASP.NET MVC应用程序里惦记着使用Repeater控件了。

此处下载源代码:http://weblogs.asp.net/blogs/stephenwalther/Downloads/Tip14/Tip14.zip

[C#]CLR系列:浅析泛型的本质

mikel阅读(942)

转载:http://www.cnblogs.com/gjcn/archive/2008/11/25/1338407.html

泛型早在.net2.0就出来了,大家已经对它的使用很熟悉了,在工作中也大量的使用过它,但是大家对其工作原理,以及MS针对泛型对CLR做了那些工作是否了解呢。本文就是对泛型的本质进行讲解,希望能对大家有所帮助。

1 引入泛型

.Net2.0出来的时候,大家很轰动,其中.NET2.0做的一个很大的改变就是增加了泛型。在1.1的版本,大家还在使用一些如:ArrayList等集合。就算现在是.net3.5的时代,还是有很多程序员在继续使用1.1版本的集合,并没有采用范型集合,毕竟一个新技术的使用是要一段时间的,也许大家看了本文后会在适当的时候使用范型。

1 ArrayList arr = new ArrayList();
2 List<int> arr1 = new List<int>();
3 for (int i = 1; i < 10; i++)
4 {
5     arr.Add(i);
6     arr1.Add(i);
7 }

这是一个很基础的泛型应用,可能大家大部分使用泛型都是类似上面的方式。我们就从这个简单的代码讲起。表面上看好像1.1版本和2.0版本的集合使用上没什么其别,一样的方便。但是实质上MS在底层做了很多复杂的工作。我们看看它的IL代码:

1 IL_0012:  ldloc.0
2 IL_0013:  ldloc.2
3 IL_0014:  box        [mscorlib]System.Int32
4 IL_0019:  callvirt   instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
5 IL_001e:  pop
6 IL_001f:  ldloc.1
7 IL_0020:  ldloc.2
8 IL_0021:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
9 

在这里我们看看它第三行,熟悉IL的人都知道。这行box是在执行装箱操作。我们可以看看的Add方法原型:

Code

我们可以看到ArrayList的Add方法的参数是object类型,我们都知道int --> object是要经过装箱操作,装箱操作又是个很费时间的事情,这就影响了性能。这里我们就引出泛型的第一个好处:性能的好处,避免了频繁的装箱拆箱操 作。泛型的第二个好处:保证了类型的绝对安全,这点就不多讲了。上面的IL里多了一个类 型:System.Collections.Generic.List`1这是.net CLR为泛型生成一个带“'”的类型,后面的数字表示<x,x>里参数x的个数。还有一个就是!0,这个是什么呢,请看下面的分析。

2 解析泛型

还是先看看一段代码:

public void intrGeneric<T>()
{
   Console.WriteLine(
typeof(T));
}
intrGeneric
<int>();
intrGeneric
<object>();
intrGeneric
<string>();

那么当我们不知道intrGeneric<T>的T的类型的时候,IL是在怎么处理的呢。看看产生的IL:

 1 .method public hidebysig instance void  intrGeneric<T>() cil managed noinlining
 2 {
 3   // Code size       18 (0x12)
 4   .maxstack  8
 5   IL_0000:  nop
 6   IL_0001:  ldtoken    !!T
 7   IL_0006:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
 8   IL_000b:  call       void [mscorlib]System.Console::WriteLine(object)
 9   IL_0010:  nop
10   IL_0011:  ret
11 // end of method Generics_CSharp::intrGeneric

 在这里我们可以看到编译器产生的IL是并没有为T指定一个特定的类型,但是输出的结果为System.Int32,System.Object,System.String。我们知道typeof()输出的Runtime Type。我们很容易的得出泛型的另外一个特性:运行时本质。由CLR运行时支持,真正的泛型实例化是发生在JIT编译时,生成不同的本地代码。我们再来看看上面的IL代码:ldtoken    !!T,ldtoken 指令:将元数据标记转换为其运行时表示形式,并将其推送到计算堆栈上。!!T时编译器生成的一个占位符,工作形式时这样的:第一次编译的时候,首先生成 IL代码以及元数据,T只是一个隐藏的符号,这是并没有对泛型类型进行实例化,当JIT编译的时候,将以实际类型替换IL代码和元数据的T符号,并将其转 换为本地代码。

 说到这里我们大概对泛型有个大概的了解。Java编译器在编译泛型的时候,会将所有的 泛型参数替换为Object,这实际上还是存在装箱拆箱的过程。还有C++的实现也存在一个很大的问题,那就是代码爆炸,C++会为每种类型都要生成自己 的一份代码。C#与JAVA比较解决了性能问题,与C++比较,解决了代码爆炸的问题。那么C#是怎么解决代码爆炸的问题,做到代码共享的呢?这也是C# 泛型的一个特性。

我们知道一个程序域有个loader heap,里面有个method table,每种类型都有自己的一个一个方法表,而且这个方法表列出所有的方法,方法表中包含了一个槽表,指向各个方法的描述MethodDesc), 提供了类型的行为能力,用于不同的交互操作实现的调用,在第一次调用时,会调用JIT编译程序,对其进行扫描,发现有引用别的类型,就会导向元数据,让后 再根据元数据导向到所要查找的类型的具体位置,当范型参数是引用类型的时候,引用类型变量都是指向托管堆的指针,(在32位的操作系统上指针都是32位 的)而对于指针完全是可以用相同的方式操作的。这再很大程度上避免了代码爆炸。如果为值类型的时候,由于值类型都是直接操作数据本身,JIT不会为一个不 知道大小的参数去产生同样的代码。下次JIT编译的时候,先去查找是否有相同的类型代码,如果有的话,就不会再次编译。因此C#泛型做到了时间和空间的双 重效应。看看下面windbg+sos的调试,我们看看它经过JIT编译过后的本地代码,我们更加肯定的验证了以上的我们所论述的。

 1 0:010> !u 00dc1128
 2 Normal JIT generated code
 3 Collections.Program.Main(System.String[])
 4 Begin 00dc1128, size 90
35 00dc117f 8bdf            mov     ebx,edi
36 00dc1181 8bce            mov     ecx,esi
37 00dc1183 3909            cmp     dword ptr [ecx],ecx
38 00dc1185 e886b4cbff      call    00a7c610 (Collections.Generics_CSharp.intrGeneric[[System.Int32, mscorlib]](), mdToken: 06000003)
39 00dc118a 90              nop
40 00dc118b 8bce            mov     ecx,esi
41 00dc118d ba2892a700      mov     edx,0A79228h (MD: Collections.Generics_CSharp.intrGeneric[[System.Object, mscorlib]]())
42 00dc1192 3909            cmp     dword ptr [ecx],ecx
43 00dc1194 e897b4cbff      call    00a7c630 (Collections.Generics_CSharp.intrGeneric[[System.__Canon, mscorlib]](), mdToken: 06000003)
44 00dc1199 90              nop
45 00dc119a 8bce            mov     ecx,esi
46 00dc119c ba6892a700      mov     edx,0A79268h (MD: Collections.Generics_CSharp.intrGeneric[[System.String, mscorlib]]())
47 00dc11a1 3909            cmp     dword ptr [ecx],ecx
48 00dc11a3 e888b4cbff      call    00a7c630 (Collections.Generics_CSharp.intrGeneric[[System.__Canon, mscorlib]](), mdToken: 06000003)
49 00dc11a8 90              nop
50 00dc11a9 e81e886278      call    mscorlib_ni+0x3299cc (793e99cc) (System.Console.Read(), mdToken: 060007b6)
51 00dc11ae 90              nop
52 00dc11af 90              nop
53 00dc11b0 8d65f4          lea     esp,[ebp-0Ch]
54 00dc11b3 5b              pop     ebx
55 00dc11b4 5e              pop     esi
56 00dc11b5 5f              pop     edi
57 00dc11b6 5d              pop     ebp
58 00dc11b7 c3              ret
59 

这里调试的正式调用泛型方法的函数,看看红色的地方,看看这三个CALL,大家可以看到第一个(int)的地址是:00a7c610 ,后面两个(object和string)的地址都是:00a7c630 。 这可以说明值类型是不同的类型生成不同的代码,而引用类型是共用一个代码。大家还可以看到mdToken: 06000003。这也说明无论是值类型还是 引用类型都是共用一个占位符,引用的是同一个类型下的方法和同一个MethodDesc,进而验证泛型是基于JIT的。

由此我们可以看出为了是泛型能够工作,MS必须做一下的工作:

创建新的IL指令,使之能够识别类型参数。

修改现有的元数据表的格式。

修改各种编程语言使他们能支持泛型。

修改编译器,能生成新的IL和元数据。

修改JIT编译器。

 以上是本人对C#泛型的一点理解。。关于泛型的特性和语法不是本文的重点,园子里有很多文章可以参考。有不同意见欢迎大家指出来。希望大家看了本文后对泛型有个更加深入的理解。

 

待续。。。

[JavaScript]Javascript版飞行射击游戏《天机》1.0正式版发布(附源代码)

mikel阅读(663)

转载:http://www.cnblogs.com/Random/archive/2008/11/24/1339648.html
《天机》的1.0正式版终于可以发布了,从0.6版到1.0版的发布,经历了3个多月近4个月的时间。倒不是因为开发了那么长时间,而是这段时间又经历了 很多事,每个时间段总是有事情要处理,是在时间间隙中开发,再加上个人在后段的开发过程中投入的精力没有之前那么多了,所以进度就稍慢了一些。
      1.0版是我发布的一个正式版,也很有可能是最终版,因为后期可能会放下这个作品,做其它想法的尝试了,而且所有代码我会也在这次发布的时候全部公布出 来。这次做了一点点优化,因为我给游戏中的每个敌人都是加了一个是否被字弹击中的侦听,之前的做法是,一个关卡的所有敌人,从一开始全部都加上侦听,这样 性能就有点低。现在的做法就是在敌人出场的时候再给它加上侦听,这样就减少了同时侦听判断数,效率上就相对高一些了。不过JS的游戏确实在图形表现上性能 还是不算太高,所以一但画面中图形数量多的话,运行速度就会明显变慢了,所以还是推荐大家用配置好一点的机器来进行测试。
      浏览器方面我尽量做到了最大兼容,目前在IE6、IE7、FF3、Opera、Safari、Chrome上都能比较好地运行,不过个人感觉在FF3和Chrome上的效果比较好,大家也可以在多个浏览器上跑一下试试。
      ok,现在把游戏的说明简单给大家介绍一下:

        操作菜单

       

 

        1 – 开始游戏
        2 – 键位设置,可以根据个人的喜好设置相应的操作按键,默认是:W-上、S-下、A-左、D-右、J-发射、K-炸弹。
        3 – 难度设置,有三个难度,如果你觉得默认的简单难度没挑战,可以选择高一点的难度,肯定不会让你失望。
        4 – 语言设置,目前支持简单中文和英文。
        5 – 关于作者
      关卡
        一共有四个关卡,关卡的顺序是随机排列的,也就是说,每次玩的时候,关卡的出现顺序都不一样,关卡越到后面,难度越大。
      金牌奖励
        游戏中击爆某些敌人,会有金牌徽章的奖励,而金牌会旋转出几种角度,每个角度的分值都不一样,玩家的飞机获取的分值由获取金牌时的角度来决定,以下是各个角度的分值:

        500分

        1000分

        2000分

          4000分

 

      增加生命
        游戏中我加入了增加生命的功能,当玩家分数达到以下几种情况的时候,会增加一条生命:
        50000,100000,150000,200000,250000,300000
      蓄力

        长按发射键大约3秒左右,会让玩家的飞机蓄力,松开发射键就会发射蓄力的子弹。

 

      以上是简单的一些介绍,还有一些功能有兴趣的同学可以慢慢体会。下面给出游戏的所有的代码和相关图片及运行地址,因为本人水平有限,所以代码可能有很多地方写得不够好,希望大家多多提意见,谢谢。

       

 

        我是源代码+图片

 

 

 

申明:该游戏的99%图像取材皆来自于“彩京”几个版本的飞行射击游戏,其版权归彩京公司所有。

   另:再次感谢小何提供的空间赞助(虽然你现在不知道我又上传了N多东西……HOHO~~~)

相关链接:天机0.6版及相关说明     天机开发手记

[JQuery]微软将 jQuery IntelliSense整合到Visual Studio

mikel阅读(790)

上个月,我在博客里宣布了微软将对JQuery提供支持。在过去的几个星期里,我们与JQuery开发团队合作,在Studio 2008 和 Visual Web Developer 2008 Express版本(免费的)中增加了很好的JQuery intellisense支持。现在这个支持可以下载使用了。
在VS 2008中启用jQuery Intellisense的步骤
要在VS中启用jQuery的intellisense完成,你要遵循三个步骤:
第一步: 安装VS 2008 SP1
VS 2008 SP1 在Visual Studio中加了更丰富的JavaScript intellisense支持,对很大部分的JavaScript库加了代码完成支持。
你可以在这里下载VS 2008 SP1 和 Visual Web Developer 2008 Express SP1。
第二步: 安装VS 2008 Patch KB958502以支持"-vsdoc.js"Intellisense文件
2 个星期前,我们发布了一个补丁,你可以将其运用到VS 2008 SP1 和 VWD 2008 Express SP1版本上,该补丁会导致Visual Studio在一个JavaScript库被引用时,查找是否存在一个可选的"-vsdoc.js"文件,如果存在的话,就用它来驱动 JavaScript intellisense引擎。
这些加了注释的"-vsdoc.js"文件可以包含对JavaScript方法提供了帮助文档的XML注释,以及对无法自动推断出的动态JavaScript签名的另外的代码intellisense提示。你可以在这里了解该补丁的详情。你可以在这里免费下载该补丁。
第三步: 下载jQuery-vsdoc.js文件
我们与jQuery开发团队合作编写了一个jQuery-vsdoc.js文件,该文件对串连的jQuery selector方法的JavaScript intellisense提供了帮助注释和支持。你可以在jQuery.com网站的官方下载网页上下载jQuery和jQuery-vsdoc文件:
把jquery-vsdoc.js保存到你项目中jquery.js文件所在的同一个目录中(同时确认它的命名前缀与jquery文件名匹配):
然后你可以象这样,通过一个html <script/>元素来引用标准的jquery文件:
或者也可以使用<asp:scriptmanager/> 控件来引用它,或者在一个单独的.js文件的顶部加 /// <reference/> 注释来引用它:
在完成之后,VS就会在你引用的脚本文件所在的同一个目录中寻找一个-vsdoc.js文件,如果找到的话,就会用它来做帮助和intellisense。
例如,我们可以使用jQuery来做一个基于JSON的get请求,得到该方法的intellisense(挂在$.之后):
以及 $.getJSON()方法参数的帮助/intellisense:
如果你在方法调用中嵌套回调函数的话,intellisense依旧会工作。例如,我们也许想对从服务器返回的每个JSON对象进行迭代:
对每个项,我们可以执行另一个嵌套的回调函数:
我们可以使用each回调函数动态地往列表中附加一个新图片(图片的src属性将指向返回的JSON媒体图片的URL):
然后在每个动态生成的图片上,我们可以连接一个点击事件处理函数,在点击时,会通过动画效果来消失:
注意jQuery intellisense在我们代码的每一个层次都很干净地做了提示。
JavaScript Intellisense 技巧和诀窍
Web工具开发团队的Jeff King本星期早先时候撰写了一个很棒的贴子,对有关VS 2008中JavaScript intellisense工作原理的若干常见的问题做了回答,我高度推荐阅读该文。
他 谈到的一个诀窍(我要在这里做示范)是在你想要在用户控件/部分(.ascx文件)中使用JavaScript intellisense时可以使用的一个技术。经常地,你不想要在这些文件中包括对JavaScript库的<script src=""/> 引用,这些引用往往是存在于使用了用户控件的母版页或内容网页之上的。当然,问题是,你这么做的话,在默认情形下VS是无法知道用户控件中用到了这个脚 本,因此不会为你提供intellisense 。
启用intellisense的一个方法是,在你的用户控件中加<script src=""/>元素,但在其周围加一个服务器端的<% if %> 块,在运行时其值总是为false:
在运行时,ASP.NET不会显示这个脚本标识(因为是包含在一个总是为false的if块中的),但是,VS却会运算这个<script/>标识,在用户控件中为它提供intellisense。在象用户控件这样的场景下,这是个非常有用的技术。Jeff在他的FAQ贴子和原先的jQuery intellisense贴子里还有更多细节。Rick Strahl在这里也有一篇很好的贴子,是关于使用jQuery intellisense的。
更多信息
想进一步了解jQuery的话,我建议观看Stephen Walther在PDC大会上做的《ASP.NET和jQuery》讲座。点击这里下载他的代码例程和 powerpoint讲义。
Rick Strahl也有一篇非常棒的《Introduction to jQuery》文章,讨论如何在 ASP.NET使用jQuery。Karl Seguin 在这里和这里有2篇非常好的jQuery基础教程贴子,对如何使用jQuery的一些基本知识提供了比较简短的的概述。
我也高度推荐《 jQuery in Action》一书。
希望本文对你有所帮助,
Scott
翻译:Scott Guthrie 博客中文版

[C#]方法的直接调用,反射调用与……Lambda表达式调用

mikel阅读(924)

转载:http://www.cnblogs.com/JeffreyZhao/archive/2008/11/22/invoke-method-by-lambda-expression.html
想调用一个方法很容易,直接代码调用就行,这人人都会。其次呢,还可以使用反射。不过通过反射调用的性能会远远低于直接调用——至少从绝对时间上来 看的确是这样。虽然这是个众所周知的现象,我们还是来写个程序来验证一下。比如我们现在新建一个Console应用程序,编写一个最简单的Call方法。

class Program
{
static void Main(string[] args)
{
}
public void Call(object o1, object o2, object o3) { }
}

  Call方法接受三个object参数却没有任何实现,这样我们就可以让测试专注于方法调用,而并非方法实现本身。于是我们开始编写测试代码,比较一下方法的直接调用与反射调用的性能差距:

static void Main(string[] args)
{
int times = 1000000;
Program program = new Program();
object[] parameters = new object[] { new object(), new object(), new object() };
program.Call(null, null, null); // force JIT-compile
Stopwatch watch1 = new Stopwatch();
watch1.Start();
for (int i = 0; i < times; i++)
{
program.Call(parameters[0], parameters[1], parameters[2]);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed + " (Directly invoke)");
MethodInfo methodInfo = typeof(Program).GetMethod("Call");
Stopwatch watch2 = new Stopwatch();
watch2.Start();
for (int i = 0; i < times; i++)
{
methodInfo.Invoke(program, parameters);
}
watch2.Stop();
Console.WriteLine(watch2.Elapsed + " (Reflection invoke)");
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}

  执行结果如下:

00:00:00.0135323 (Directly invoke)
00:00:05.2325120 (Reflection invoke)
Press any key to continue...

  通过各调用一百万次所花时间来看,两者在性能上具有数量级的差距。因此,很多框架在必须利用到反射的场景中,都会设法使用一些较高级的替代方案 来改善性能。例如,使用CodeDom生成代码并动态编译,或者使用Emit来直接编写IL。不过自从.NET 3.5发布了Expression相关的新特性,我们在以上的情况下又有了更方便并直观的解决方案。

  了解Expression相关特性的朋友可能知 道,System.Linq.Expressions.Expression<TDelegate>类型的对象在调用了它了Compile方 法之后将得到一个TDelegate类型的委托对象,而调用一个委托对象与直接调用一个方法的性能开销相差无几。那么对于上面的情况,我们又该得到什么样 的Delegate对象呢?为了使解决方案足够通用,我们必须将各种签名的方法统一至同样的委托类型中,如下:

public Func<object, object[], object> GetVoidDelegate()
{
Expression<Action<object, object[]>> exp = (instance, parameters) =>
((Program)instance).Call(parameters[0], parameters[1], parameters[2]);
Action<object, object[]> action = exp.Compile();
return (instance, parameters) =>
{
action(action, parameters);
return null;
};
}

  如上,我们就得到了一个Func<object, object[], object>类型的委托,这意味它接受一个object类型与object[]类型的参数,以及返回一个object类型的结果——等等,朋友们 有没有发现,这个签名与MethodInfo类型的Invoke方法完全一致?不过可喜可贺的是,我们现在调用这个委托的性能远高于通过反射来调用了。那 么对于有返回值的方法呢?那构造一个委托对象就更方便了:

public int Call(object o1, object o2) { return 0; }
public Func<object, object[], object> GetDelegate()
{
Expression<Func<object, object[], object>> exp = (instance, parameters) =>
((Program)instance).Call(parameters[0], parameters[1]);
return exp.Compile();
}

  至此,我想朋友们也已经能够轻松得出调用静态方法的委托构造方式了。可见,这个解决方案的关键在于构造一个合适的Expression<TDelegate>,那么我们现在就来编写一个DynamicExecuter类来作为一个较为完整的解决方案:

public class DynamicExecutor
{
private Func<object, object[], object> m_execute;
public DynamicExecutor(MethodInfo methodInfo)
{
this.m_execute = this.GetExecuteDelegate(methodInfo);
}
public object Execute(object instance, object[] parameters)
{
return this.m_execute(instance, parameters);
}
private Func<object, object[], object> GetExecuteDelegate(MethodInfo methodInfo)
{
// parameters to execute
ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");
ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
// build parameter list
List<Expression> parameterExpressions = new List<Expression>();
ParameterInfo[] paramInfos = methodInfo.GetParameters();
for (int i = 0; i < paramInfos.Length; i++)
{
// (Ti)parameters[i]
BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
UnaryExpression valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType);
parameterExpressions.Add(valueCast);
}
// non-instance for static method, or ((TInstance)instance)
Expression instanceCast = methodInfo.IsStatic ? null :
Expression.Convert(instanceParameter, methodInfo.ReflectedType);
// static invoke or ((TInstance)instance).Method
MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, parameterExpressions);
// ((TInstance)instance).Method((T0)parameters[0], (T1)parameters[1], ...)
if (methodCall.Type == typeof(void))
{
Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(
methodCall, instanceParameter, parametersParameter);
Action<object, object[]> execute = lambda.Compile();
return (instance, parameters) =>
{
execute(instance, parameters);
return null;
};
}
else
{
UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
Expression<Func<object, object[], object>> lambda = Expression.Lambda<Func<object, object[], object>>(
castMethodCall, instanceParameter, parametersParameter);
return lambda.Compile();
}
}
}

  DynamicExecutor的关键就在于GetExecuteDelegate方法中构造Expression Tree的逻辑。如果您对于一个Expression Tree的结构不太了解的话,不妨尝试一下使用Expression Tree Visualizer来 对一个现成的Expression Tree进行观察和分析。我们将一个MethodInfo对象传入DynamicExecutor的构造函数之后,就能将各组不同的实例对象和参数对象数 组传入Execute进行执行。这一切就像使用反射来进行调用一般,不过它的性能就有了明显的提高。例如我们添加更多的测试代码:

DynamicExecutor executor = new DynamicExecutor(methodInfo);
Stopwatch watch3 = new Stopwatch();
watch3.Start();
for (int i = 0; i < times; i++)
{
executor.Execute(program, parameters);
}
watch3.Stop();
Console.WriteLine(watch3.Elapsed + " (Dynamic executor)");

  现在的执行结果则是:

00:00:00.0148828 (Directly invoke)
00:00:05.2488540 (Reflection invoke)
00:00:00.0618695 (Dynamic executor)
Press any key to continue...

  事实上,Expression<TDelegate>类型的Compile方法正是使用Emit来生成委托对象。不过现在我们已经 无需将目光放在更低端的IL上,只要使用高端的API来进行Expression Tree的构造,这无疑是一种进步。不过这种方法也有一定局限性,例如我们只能对公有方法进行调用,并且除了方法外的其他类型成员,我们就无法如上例般惬 意地编写代码了。

[C#]利用虚拟方法和反射简化Alisoft API的调用

mikel阅读(933)

利用虚拟方法和反射简化Alisoft API的调用

转载:http://www.cnblogs.com/doublog/archive/2008/11/21/1338065.html

最近一直在研究Alisfot api,他的文档和帮助都让我很郁闷,可能是第一次做这种开放api的程序吧.为了简化那些烦人的参数和返回值的调用,可以利用.net的匿名委托和反射机制来达到目的,简化后代码可以如下所示:

/// <summary>

/// 此接口方法以实现得到前台展示的店铺内卖家自定义商品类目。

/// </summary>

/// <param name="Nick"></param>

/// <returns></returns>

public List<SellerCat> sellercats_list_get(string Nick)

{

SellerCatsPar parSL = new SellerCatsPar();

parSL.sip_sessionid = sip_sessionid;

parSL.nick = Nick;

return APIUtils.Result<List<SellerCat>>(parSL, (string result) =>

{

NameValueCollection par = new NameValueCollection();

par.Add("ID", "cid");

par.Add("Name", "name");

par.Add("ParentID", "parent_cid");

return new XmlHandler<SellerCat>().ListItemByXml(result, "rsp/seller_cat", par);

});

}

现在是不是简单明了,只要关注于业务就可以啦.

   

第一次用office发文章,太晚了先发一点内容测试测试.:-)

据说 还能贴图 试试

图一

图一为阿里的API文档菜单,我看了一星期,硬没找到他的api列表(中间一直在看百度搜索到的一个老界面).今天才搞明白,原来我一直在 点右边红框的文字部分,他的内容竟然也变,但是树形菜单不会下拉.只有再点左边的图片才可以.也可以说是我智商的问题,但这里面也有一个用户体验的问题. 在做系统的时候会习惯的认为用户会按照自己的思维做事情,往往一个简单的东西,不同的人就会得到不同的结果.比如这个问题.如果不是因为我继续关注,阿里 的这个api我肯定会以为他没提供而放弃找其他的啦.

[Flex]Ensemble Visual Studio 的Flex插件

mikel阅读(1003)

转载自:http://www.asflex.cn/?p=589

今天在Forbes.com上看到《Ensemble Introduces Tofino, A Visual Studio Plug-In for Flex Applications

翻译一下吧。

Flex 是一个用于开发和维护Web程序(支持大部分的浏览器,桌面和操作系统)的免费开源框架。目前,大部分的Flex开发者都使用基于Eclipse(TM) 的Adobe(R) Flex(R) Builder(TM),用来开发、调试、部署RIA程序。为了让开发者使用Visual Studio,Ensemble Tofino提供了一个.Net的解决方案,让在.Net开发环境中开发Flex成为了可能。

“我们相信Ensemble Tofino将会帮助.Net开发者,因为使用相同的开发界面而不需要手动地调用Flex编译器,从而非常容易地将Flex的优点和.Net服务器语言联合起来。”,Ensemble 的主要技术部门负责人Ray Blaak说。

Tofino提供了一个 强劲的智能化编码和调试功能,同时可以通过Visual Studio相当创建项目。同时可以在Visual Studio中运行Flex程序,支持调试断点和堆栈信息显示,并且将会在Visual Studio的错误信息列表中显示错误信息。Tofino将会通过开源的Flex框架的形式向用户发放。

“我们知道许多的 Visual Studio开发者希望使用Flex去开发同类最佳的程序,同时也希望使用他们已经非常熟悉的工具”,Adobe 的产品经理Greg DeMichillie说,”我们非常荣幸地介绍Ensemble  Tofino,因为它使得Visual Studio开发者充分地使用Flex去开发企业级应用程序”.

目前Ensemble Tofino还是第一个Beta版本,同时后续的开发版本将持续得提高开发体验。更多的信息和下载在:http://www.ensemble.com

关于Ensemble

Ensemble (www.ensemble.com) 是一个Adobe的开发伙伴,专注于需求分析,体系结构,执行,部署所有的Adobe技术。特别是在Adobe(R) LiveCycle(R), Adobe(R) Flex(R), Adobe(R) AIR(TM)和Adobe(R) Acrobat(R)的集成方案.在政府,金融服务,媒体,公共出版和制造业部署Adobe技术拥有非常丰富的经验。基于 Vancouver,British Columbia,我们满足世界上任何地方人们的需要。

Tofino(82.59MB)下载:

http://www.ensemble.com/downloadables/products/Tofino/EnsembleTofino.msi

Attention:只支持Visual Studio 2008 /Windows Vista/XP

[Flash]MAX大会新闻

mikel阅读(800)

Cocomo发布beta版
http://www.flashcomguru.com/index.cfm/2008/11/17/cocomo-public-beta
Flash Media Server 3.5正式版公布
http://www.flashcomguru.com/index.cfm/2008/11/17/fms3_5-announced
Adobe air 1.5发布
http://get.adobe.com/air/
Thermo取名为Catalyst
http://labs.adobe.com/technologies/flashcatalyst
Flash Catalyst 小组博客
http://thermoteamblog.com/
Adobe与ARM联手提升手机上网体验
http://www.cnbeta.com/article.php?sid=69982
Adobe将发布Windows Mobile版Flash Player
http://www.cnbeta.com/article.php?sid=69970
Adobe Flash视频是否能如愿出现在iPhone上?
http://www.cnbeta.com/article.php?sid=70030
ColdFusion 新的IDE
New ColdFusion IDE Announced ("Bolt")

http://www.adobe.com/go/boltprerelease
http://labs.adobe.com/wiki/index.php/Bolt
C++ To AVM : Alchemy
http://labs.adobe.com/technologies/alchemy/
Server Side ActionScript 3.0: Coming to a ColdFusion Server Near You
http://www.joeflash.ca/blog/2008/11/61.html

[SQL]Select查询原理

mikel阅读(948)

转载自:http://www.cnblogs.com/ASPNET2008/archive/2008/11/19/1336329.html   
 我并非专业DBA,但做为B/S架构的开发人员,总是离不开数据库,一般开发员只会应用SQL的四条经典语句:select ,insert,delete,update。但是我从来没有研究过它们的工作原理,这篇我想说一说select在数据库中的工作原理。B/S架构中最经 典的话题无非于三层架构,可以大概分为数据层,业务逻辑层和表示层,而数据层的作用一般都是和数据库交互,例如查询记录。
      我们经常是写好查询SQL,然后调用程序执行SQL。但是它内部的工作流程是怎样的呢?先做哪一步,然后做哪一步等,我想还有大部分朋友和我一样都不一定清楚。 

     第一步:应用程序把查询SQL语句发给服务器端执行。

                我们在数据层执行SQL语句时,应用程序会连接到相应的数据库服务器,把SQL语句发送给服务器处理。

     第二步:服务器解析请求的SQL语句。

                1:SQL计划缓存,经常用查询分析器的朋友大概都知道这样一个事实,往往一个查询语句在第一次运行的时候需要执行特别长的时间,但是如果你马上或者在一定时间内运行同样的语句,会在很短的时间内返回查询结果。   

      

                 原因:

                     1):服务器在接收到查询请求后,并不会马上去数据库查询,而是在数据库中的计划缓存中找是否有相对应的执行计划,如果存在,就直接调用已经编译好的执行计划,节省了执行计划的编译时间。
                     2):如果所查询的行已经存在于数据缓冲存储区中,就不用查询物理文件了,而是从缓存中取数据,这样从内存中取数据就会比从硬盘上读取数据快很多,提高了查询效率.数据缓冲存储区会在后面提到。

               2:如果在SQL计划缓存中没有对应的执行计划,服务器首先会对用户请求的SQL语句进行语法效验,如果有语法错误,服务器会结束查询操作,并用返回相应的错误信息给调用它的应用程序。

                 注意:此时返回的错误信息中,只会包含基本的语法错误信息,例如select 写成selec等,错误信息中如果包含一列表中本没有的列,此时服务器是不会检查出来的,因为只是语法验证,语义是否正确放在下一步进行。
               3:语法符合后,就开始验证它的语义是否正确,例如,表名,列名,存储过程等等数据库对象是否真正存在,如果发现有不存在的,就会报错给应用程序,同时结束查询。
               4:接下来就是获得对象的解析锁,我们在查询一个表时,首先服务器会对这个对象加锁,这是为了保证数据的统一性,如果不加锁,此时有数据插入,但因为没有加锁的原因,查询已经将这条记录读入,而有的插入会因为事务的失败会回滚,就会形成脏读的现象。
               5:接下来就是对数据库用户权限的验证,SQL 语句语法,语义都正确,此时并不一定能够得到查询结果,如果数据库用户没有相应的访问权限,服务器会报出权限不足的错误给应用程序,在稍大的项目中,往往 一个项目里面会包含好几个数据库连接串,这些数据库用户具有不同的权限,有的是只读权限,有的是只写权限,有的是可读可写,根据不同的操作选取不同的用户 来执行,稍微不注意,无论你的SQL语句写的多么完善,完美无缺都没用。
              6:解析的最后一步,就是确定最终的执行计划。 当语法,语义,权限都验证后,服务器并不会马上给你返回结果,而是会针对你的SQL进行优化,选择不同的查询算法以最高效的形式返回给应用程序。例如在做 表联合查询时,服务器会根据开销成本来最终决定采用hash join,merge join ,还是loop join,采用哪一个索引会更高效等等,不过它的自动化优化是有限的,要想写出高效的查询SQL还是要优化自己的SQL查询语句。
             当确定好执行计划后,就会把这个执行计划保存到SQL计划缓存中,下次在有相同的执行请求时,就直接从计划缓存中取,避免重新编译执行计划。
  第三步:语句执行。
              服务器对SQL语句解析完成后,服务器才会知道这条语句到底表态了什么意思,接下来才会真正的执行SQL语句。
   些时分两种情况:

            1):如果查询语句所包含的数据行已经读取到数据缓冲存储区的话,服务器会直接从数据缓冲存储区中读取数据返回给应用程序,避免了从物理文件中读取,提高查询速度。

            2):如果数据行没有在数据缓冲存储区中,则会从物理文件中读取记录返回给应用程序,同时把数据行写入数据缓冲存储区中,供下次使用。
            说明:SQL缓存分好几种,这里有兴趣的朋友可以去搜索一下,有时因为缓存的存在,使得我们很难马上看出优化的结果,因为第二次执行因为有缓存的存在,会特别快速,所以一般都是先消除缓存,然后比较优化前后的性能表现,这里有几个常用的方法:
DBCC DropCLEANBUFFERS
从缓冲池中删除所有清除缓冲区。
DBCC FREEPROCCACHE
从过程缓存中删除所有元素。
DBCC FREESYSTEMCACHE

  从所有缓存中释放所有未使用的缓存条目。SQL Server 2005 数据库引擎会事先在后台清理未使用的缓存条目,以使内存可用于当前条目。但是,可以使用此命令从所有缓存中手动删除未使用的条目。

 

    这只能基本消除SQL缓存的影响,目前好像没有完全消除缓存的方案,如果大家有,请指教。
     结论:只有知道了服务执行应用程序提交的SQL的操作流程才能很好的调试我们的应用程序。
            1:确保SQL语法正确;
            2:确保SQL语义上的正确性,即对象是否存在;
            3:数据库用户是否具有相应的访问权限。

注:

   本文引用:

http://database.ctocio.com.cn/tips/210/7791210.shtml
http://tech.it168.com/a2008/0805/199/000000199573.shtml