- 浏览: 3047677 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
深感一口气吃不成胖子的郁闷……要是时间能停下来让我慢慢想就好了。
之前留意到ray_linn在这边的留言,提到AOP的需求:希望能找到一种办法来自动生成待注入的IL,然后利用Mono.Cecil来实现这个注入。Cecil本身功能还不错,但是在插入代码时,必须要自己来组装IL,这对不熟悉IL的开发者来说是个挑战,对熟悉IL的开发者来说也并不总是让人高兴的事吧。最好就是能用什么更高级的语言来编写待注入的代码,例如说使用C#本身。
要把高级语言翻译成IL,无非就是进行了编译的工作。在.NET Framework提供的现成的工具中,有三种办法可以实现这个编译:
1、从外部编译出IL
2、使用System.CodeDom来生成IL
3、使用C# 3.0的lambda expression,配合System.Linq.Expressions.Expression<TDelegate>来生成IL
当然咯,要是有毅力自己写一个编译器也不是不行……时间、精力、毅力,缺一不可。
所以还是把自己写编译器的选项放在一边,看看上面三种选择分别是个什么状况:
1、从外部编译出IL
可以把待注入的代码放在一个特定名字的方法里,从外部让C#编译器编译出整个assembly,然后再通过反射找到那个特定方法,并提取其中的IL。
过程类似这样:
先定义个占位用的接口:
然后实现这个接口,并从外部调用csc(.NET Framework的C#编译器)或mcs(Mono的C#编译器)来编译下面的代码,得到一个assembly:
得到了编译好的assembly之后,另外写一个程序来抽取其中的内容:
这种办法挺RP的。好处是我们熟悉的开发环境还是可以用,而且错误也会在编译时被捕捉到,但是要从外部调用编译器而不是在程序内部调用,可以控制的程度就降低了。
当然我们可以把待注入的代码的那个dummy类跟进行注入的类放在同一个文件里(或者广义来说,放在同一个assembly),就不用像上面描述的那样分开编译,但本质上还是一样的。
2、使用System.CodeDom来生成IL
例子请看这里。
使用System.CodeDom,我们可以轻松的把C#或者VB.NET的代码编译为assembly。相对前一种方法而言,使用System.CodeDom给予了我们更好的控制力;我们是直接在代码里调用编译器的,而且生成的assembly也不一定要以文件形式保存到磁盘上,而是可以直接在内存生成并使用。
但是问题也很明显:编译用的源代码,要么要以字符串的形式存在,要么要放在别的文件里。如果把源代码放在一个字符串里,那IDE就没办法对那字符串里的内容提供任何语法高亮之类的功能了——那就是一字符串。如果在字符串里打错了点什么,也必须到运行我们对System.CodeDom的调用时才能够发现。如果要把需要注入的源代码放在别的文件里的话,那还不如直接用前一种方法了,反正麻烦程度都差不多……
顺带一提,Sebastien Lebreton所写的Reflexil也是用System.CodeDom来进行代码生成的。具体的代码在/Compilation/Compiler.cs里。
同时,Reflexil也用到了Cecil。下面引用/Utils/CecilHelpers.cs的一段代码(GPLv3):
留意到它使用System.CodeDom与Cecil的方式:先利用System.CodeDom在另一个AppDomain生成了一个临时的assembly,然后利用Cecil找到那个assembly中要找的新的源方法,整个复制到目标方法里去,同时修正参数类型的不匹配。
这种方式的实现使得Reflexil只能整个方法替换,而没办法做真正的代码注入;不过跟Reflector一起用的话,这倒不是什么问题:反正Reflector能反编译出C#代码,那就把反编译出来的代码复制到新注入的代码中就是了。
但是……要是能有什么别的更自动的办法就好了。
3、使用C# 3.0的lambda expression,配合System.Linq.Expressions.Expression<TDelegate>来生成IL
C# 3.0中的expression tree相当的有趣。
当一个lambda expression被赋值给一个delegate类型,例如Action<T>或者Func<T, TResult>等,这个lambda expression会被编译器直接编译为
1) 当lambda expression没有使用闭包内的非局部引用也没有使用到this时,编译为一个私有静态方法;
2) 当lambda expression没有使用闭包内的非局部引用,但用到了this时,编译为一个私有成员方法;
3) 当lambda expression中引用到非局部变量,则编译为一个私有的内部类,将引用到的非局部变量提升为内部类的成员变量,将表达式的内容封装到内部类里的一个成员方法。
以前我在这里稍微讨论过相关的一些问题,可以参考一下。
不过,当一个lambda expression被赋值给一个System.Linq.Expressions.Expression<TDelegate>类型时,表达式的内容会被编译为一棵expression tree,而不会在编译时为其生成IL。直到真的调用那个Expression时才会进行到IL的编译。
用一段小程序来演示这个特性。
先把一个lambda expression((x, y) => x << y)赋值给一个delegate,Func<int, int, int>:
编译后再利用Reflector反编译,会看到多了一个私有静态方法<Main>b__0,还有一个缓存这个delegate的一个私有成员域:
留意到,上面的代码里同时使用了MethodBase.Invoke()(实际上是RuntimeMethodInfo.Invoke())与直接用括号的方式来调用那个delegate,运行的结果都是一样的。
把lambda expression改为赋值给Expression<Func<int, int, int>>的话:
则会发现那个表达式并没有被编译为IL,而是生成了一棵expression tree:
这棵“树”的表现方式不习惯的话可能会觉得有点怪。其实就是用括号来表示的树而已,没什么特别的。LINQ里的expression tree整个是静态类型的。这个问题以后写关于DLR的笔记的时候再讨论。
留意到这里得到的方法名跟前一个例子不一样了,expression tree通过Compile()方法被编译为IL,赋值给了一个Func<int, int, int>类型的delegate。不过却无法使用MethodBase.Invoke()(实际上是RTDynamicMethod.Invoke())来进行调用。
在.NET Reference Source Code, System.Reflection.Emit.DynamicMethod.cs里有这样一段代码:
这段注释在这个文件里出现了好几次。反正就是不让直接用RTDynamicMethod来Invoke。直接用括号来对delegate调用倒是没问题。
说到底,我们只是要编译后的IL而已,能否直接Invoke没什么关系。
这个时候,可以通过DynamicMethod.GetMethodBody()来得到一个MethodBody,然后通过MethodBody.GetILAsByteArray()来获得IL所在的byte数组。
可是……拿到了byte数组,如何能让Cecil识别出来呢?这个就等到下次再写吧~
嗯,肯定会有人问说用这个lambda expression搭配LINQ的expression tree到底有什么好处。这个问题我一时也没想得特别清楚。我的几个出发点是:
1) lambda expression可以减少名字冲突的可能性。如果要注入的目标有好几个不同的地方,无论是外部编译还是用System.CodeDom,势必要为每个注入的位置都生成一次assembly,很麻烦,而且要想办法避免类型/方法名潜在的冲突的可能。
2) 生成时,最好能不生成完整的assembly,而是只生成方法。无论是外部编译还是System.CodeDom生成的都是完整的assembly,在这里算是overkill了。我们要的只是那个方法的内容而已。从一个delegate我们可以直接获取它的MethodInfo,进而得到MethodBody、byte[]等等,不用再花功夫跑到生成出来的assembly里去慢慢找我们要的方法……
3) lambda expression转换成expression tree之后,是被动态编译为IL的,但在编译时却能检查到语法错误。这要分开两方面看:
3a) lambda expression是C#语法的一部分,所以在编译时会被编译器检查。这样就不会像用System.CodeDom那样遇到缺乏IDE支持之类的问题了。
3b) expression tree既可以由lambda expression生成,也可以动态组装。相比之下,LINQ的expression tree比IL高级,组装起来也方便许多。假如做出一个什么InjectionCodeBuilder之类的,接受expression tree为参数的话,就既能照顾到编译时的lambda expression,也能照顾到运行时自行组装的expression tree。调用一个现成的Compile()方法就能编译为IL,何乐而不为呢。
P.S. 说到AOP,我不是不知道PostSharp……不过它在内部到底是怎么实现的我还没看清楚。这库的代码量也不小啊(晕乎
PostSharp Core里的code model和weaver大概是值得关注的点吧。
总之自己要是能做一个不同的AOP实现的话,总也是件有趣的事 ^ ^
之前留意到ray_linn在这边的留言,提到AOP的需求:希望能找到一种办法来自动生成待注入的IL,然后利用Mono.Cecil来实现这个注入。Cecil本身功能还不错,但是在插入代码时,必须要自己来组装IL,这对不熟悉IL的开发者来说是个挑战,对熟悉IL的开发者来说也并不总是让人高兴的事吧。最好就是能用什么更高级的语言来编写待注入的代码,例如说使用C#本身。
要把高级语言翻译成IL,无非就是进行了编译的工作。在.NET Framework提供的现成的工具中,有三种办法可以实现这个编译:
1、从外部编译出IL
2、使用System.CodeDom来生成IL
3、使用C# 3.0的lambda expression,配合System.Linq.Expressions.Expression<TDelegate>来生成IL
当然咯,要是有毅力自己写一个编译器也不是不行……时间、精力、毅力,缺一不可。
所以还是把自己写编译器的选项放在一边,看看上面三种选择分别是个什么状况:
1、从外部编译出IL
可以把待注入的代码放在一个特定名字的方法里,从外部让C#编译器编译出整个assembly,然后再通过反射找到那个特定方法,并提取其中的IL。
过程类似这样:
先定义个占位用的接口:
public interface IInjectionWrapper { void CodeToBeInjected( ); // make an ugly name to avoid name clashing }
然后实现这个接口,并从外部调用csc(.NET Framework的C#编译器)或mcs(Mono的C#编译器)来编译下面的代码,得到一个assembly:
public class CodeInjectionDummy : IInjectionWrapper { public void CodeToBeInjected( ) { // some code here // for now let's just print some meaningless message System.Console.WriteLine( "Dummy message" ); } }
得到了编译好的assembly之后,另外写一个程序来抽取其中的内容:
using Mono.Cecil; using Mono.Cecil.Cil; // ...... // get the dummy assembly AssemblyDefinition assembly = AssemblyFactory.GetAssembly( "CodeInjectionDummy.dll" ); // get the dummy method MethodDefinition method = assembly.MainModule.Types[ "CodeInjectionDummy" ] .GetMethod( "CodeToBeInjected", new Type[] { } ); // do whatever necessary with the instructions // for now let's just print them out... foreach ( Instruction ins in method.Body.Instructions ) { Console.WriteLine( "IL_{0}: {1}\t{2}", ins.Offset.ToString( "x4" ), ins.OpCode.Name, ins.Operand is string ? string.Format( "\"{0}\"", ins.Operand ) : ins.Operand ); }
这种办法挺RP的。好处是我们熟悉的开发环境还是可以用,而且错误也会在编译时被捕捉到,但是要从外部调用编译器而不是在程序内部调用,可以控制的程度就降低了。
当然我们可以把待注入的代码的那个dummy类跟进行注入的类放在同一个文件里(或者广义来说,放在同一个assembly),就不用像上面描述的那样分开编译,但本质上还是一样的。
2、使用System.CodeDom来生成IL
例子请看这里。
使用System.CodeDom,我们可以轻松的把C#或者VB.NET的代码编译为assembly。相对前一种方法而言,使用System.CodeDom给予了我们更好的控制力;我们是直接在代码里调用编译器的,而且生成的assembly也不一定要以文件形式保存到磁盘上,而是可以直接在内存生成并使用。
但是问题也很明显:编译用的源代码,要么要以字符串的形式存在,要么要放在别的文件里。如果把源代码放在一个字符串里,那IDE就没办法对那字符串里的内容提供任何语法高亮之类的功能了——那就是一字符串。如果在字符串里打错了点什么,也必须到运行我们对System.CodeDom的调用时才能够发现。如果要把需要注入的源代码放在别的文件里的话,那还不如直接用前一种方法了,反正麻烦程度都差不多……
顺带一提,Sebastien Lebreton所写的Reflexil也是用System.CodeDom来进行代码生成的。具体的代码在/Compilation/Compiler.cs里。
同时,Reflexil也用到了Cecil。下面引用/Utils/CecilHelpers.cs的一段代码(GPLv3):
#region " Method body import " /// <summary> /// Clone a source method body to a target method definition. /// Field/Method/Type references are corrected /// </summary> /// <param name="source">Source method definition</param> /// <param name="target">Target method definition</param> public static void ImportMethodBody( MethodDefinition source, MethodDefinition target ) { // All i want is already in Mono.Cecil, but not accessible. // Reflection is my friend object context = new ImportContext( new DefaultImporter( target.DeclaringType.Module ) ); Type contexttype = context.GetType( ); Type mbodytype = typeof( Mono.Cecil.Cil.MethodBody ); MethodInfo clonemethod = mbodytype.GetMethod( "Clone", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[ ] { mbodytype, typeof( MethodDefinition ), contexttype }, null ); Mono.Cecil.Cil.MethodBody newBody = clonemethod.Invoke( null, new object[ ] { source.Body, target, context } ) as Mono.Cecil.Cil.MethodBody; target.Body = newBody; // Then correct fields and methods references foreach ( Instruction ins in newBody.Instructions ) { if ( ins.Operand is TypeReference ) { TypeReference tref = ins.Operand as TypeReference; if ( tref.FullName == source.DeclaringType.FullName ) { ins.Operand = target.DeclaringType; } } else if ( ins.Operand is FieldReference ) { FieldReference fref = ins.Operand as FieldReference; if ( fref.DeclaringType.FullName == source.DeclaringType.FullName ) { ins.Operand = FindMatchingField( target.DeclaringType as TypeDefinition, fref ); } } else if ( ins.Operand is MethodReference ) { MethodReference mref = ins.Operand as MethodReference; if ( mref.DeclaringType.FullName == source.DeclaringType.FullName ) { ins.Operand = FindMatchingMethod( target.DeclaringType as TypeDefinition, mref ); } } } } #endregion
留意到它使用System.CodeDom与Cecil的方式:先利用System.CodeDom在另一个AppDomain生成了一个临时的assembly,然后利用Cecil找到那个assembly中要找的新的源方法,整个复制到目标方法里去,同时修正参数类型的不匹配。
这种方式的实现使得Reflexil只能整个方法替换,而没办法做真正的代码注入;不过跟Reflector一起用的话,这倒不是什么问题:反正Reflector能反编译出C#代码,那就把反编译出来的代码复制到新注入的代码中就是了。
但是……要是能有什么别的更自动的办法就好了。
3、使用C# 3.0的lambda expression,配合System.Linq.Expressions.Expression<TDelegate>来生成IL
C# 3.0中的expression tree相当的有趣。
当一个lambda expression被赋值给一个delegate类型,例如Action<T>或者Func<T, TResult>等,这个lambda expression会被编译器直接编译为
1) 当lambda expression没有使用闭包内的非局部引用也没有使用到this时,编译为一个私有静态方法;
2) 当lambda expression没有使用闭包内的非局部引用,但用到了this时,编译为一个私有成员方法;
3) 当lambda expression中引用到非局部变量,则编译为一个私有的内部类,将引用到的非局部变量提升为内部类的成员变量,将表达式的内容封装到内部类里的一个成员方法。
以前我在这里稍微讨论过相关的一些问题,可以参考一下。
不过,当一个lambda expression被赋值给一个System.Linq.Expressions.Expression<TDelegate>类型时,表达式的内容会被编译为一棵expression tree,而不会在编译时为其生成IL。直到真的调用那个Expression时才会进行到IL的编译。
用一段小程序来演示这个特性。
先把一个lambda expression((x, y) => x << y)赋值给一个delegate,Func<int, int, int>:
using System; using System.Linq.Expressions; using System.Reflection; namespace TestLinqExpression { class Program { static void Main(string[] args) { Func<int, int, int> shlFunc = (x, y) => x << y; MethodInfo method = shlFunc.Method; // gets a RuntimeMethodInfo instance Console.WriteLine(method); // Int32 <Main>b__0(Int32, Int32) Console.WriteLine(method.Invoke(null, new object[] { 3, 2 })); // 12 Console.WriteLine(shlFunc(3, 2)); // 12 } } }
编译后再利用Reflector反编译,会看到多了一个私有静态方法<Main>b__0,还有一个缓存这个delegate的一个私有成员域:
internal class Program { // Methods private static void Main(string[] args) { Func<int, int, int> shlFunc = delegate (int x, int y) { return x << y; }; MethodInfo method = shlFunc.Method; Console.WriteLine(method); Console.WriteLine(method.Invoke(null, new object[] { 3, 2 })); Console.WriteLine(shlFunc(3, 2)); } [CompilerGenerated] private static int <Main>b__0(int x, int y) { return (x << y); } [CompilerGenerated] private static Func<int, int, int> CS$<>9__CachedAnonymousMethodDelegate1; }
留意到,上面的代码里同时使用了MethodBase.Invoke()(实际上是RuntimeMethodInfo.Invoke())与直接用括号的方式来调用那个delegate,运行的结果都是一样的。
把lambda expression改为赋值给Expression<Func<int, int, int>>的话:
using System; using System.Linq.Expressions; using System.Reflection; namespace TestLinqExpression { class Program { static void Main( string[ ] args ) { Expression<Func<int, int, int>> shlExp = ( x, y ) => x << y; Func<int, int, int> shlFunc = shlExp.Compile( ); MethodInfo method = shlFunc.Method; // gets a DynamicMethod.RTDynamicMethod instance Console.WriteLine( method ); // Int32 lambda_method(System.Runtime.CompilerServices.ExecutionScope, Int32, Int32) // Console.WriteLine( method.Invoke( null, new object[ ] { 3, 2 } ) ); // throws ArgumentException Console.WriteLine( shlFunc( 3, 2 ) ); // 12 } } }
则会发现那个表达式并没有被编译为IL,而是生成了一棵expression tree:
internal class Program { // Methods private static void Main(string[] args) { ParameterExpression CS$0$0000; ParameterExpression CS$0$0001; Func<int, int, int> shlFunc = Expression.Lambda<Func<int, int, int>>( Expression.LeftShift( CS$0$0000 = Expression.Parameter(typeof(int), "x"), CS$0$0001 = Expression.Parameter(typeof(int), "y")), new ParameterExpression[] { CS$0$0000, CS$0$0001 }).Compile(); MethodInfo method = shlFunc.Method; Console.WriteLine(method); // Console.WriteLine(method.Invoke(null, new object[] { 3, 2 })); Console.WriteLine(shlFunc(3, 2)); } }
这棵“树”的表现方式不习惯的话可能会觉得有点怪。其实就是用括号来表示的树而已,没什么特别的。LINQ里的expression tree整个是静态类型的。这个问题以后写关于DLR的笔记的时候再讨论。
留意到这里得到的方法名跟前一个例子不一样了,expression tree通过Compile()方法被编译为IL,赋值给了一个Func<int, int, int>类型的delegate。不过却无法使用MethodBase.Invoke()(实际上是RTDynamicMethod.Invoke())来进行调用。
在.NET Reference Source Code, System.Reflection.Emit.DynamicMethod.cs里有这样一段代码:
public override Object Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) { // We want the creator of the DynamicMethod to control who has access to the // DynamicMethod (just like we do for delegates). However, a user can get to // the corresponding RTDynamicMethod using Exception.TargetSite, StackFrame.GetMethod, etc. // If we allowed use of RTDynamicMethod, the creator of the DynamicMethod would // not be able to bound access to the DynamicMethod. Hence, we do not allow // direct use of RTDynamicMethod. throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"), "this"); }
这段注释在这个文件里出现了好几次。反正就是不让直接用RTDynamicMethod来Invoke。直接用括号来对delegate调用倒是没问题。
说到底,我们只是要编译后的IL而已,能否直接Invoke没什么关系。
这个时候,可以通过DynamicMethod.GetMethodBody()来得到一个MethodBody,然后通过MethodBody.GetILAsByteArray()来获得IL所在的byte数组。
可是……拿到了byte数组,如何能让Cecil识别出来呢?这个就等到下次再写吧~
嗯,肯定会有人问说用这个lambda expression搭配LINQ的expression tree到底有什么好处。这个问题我一时也没想得特别清楚。我的几个出发点是:
1) lambda expression可以减少名字冲突的可能性。如果要注入的目标有好几个不同的地方,无论是外部编译还是用System.CodeDom,势必要为每个注入的位置都生成一次assembly,很麻烦,而且要想办法避免类型/方法名潜在的冲突的可能。
2) 生成时,最好能不生成完整的assembly,而是只生成方法。无论是外部编译还是System.CodeDom生成的都是完整的assembly,在这里算是overkill了。我们要的只是那个方法的内容而已。从一个delegate我们可以直接获取它的MethodInfo,进而得到MethodBody、byte[]等等,不用再花功夫跑到生成出来的assembly里去慢慢找我们要的方法……
3) lambda expression转换成expression tree之后,是被动态编译为IL的,但在编译时却能检查到语法错误。这要分开两方面看:
3a) lambda expression是C#语法的一部分,所以在编译时会被编译器检查。这样就不会像用System.CodeDom那样遇到缺乏IDE支持之类的问题了。
3b) expression tree既可以由lambda expression生成,也可以动态组装。相比之下,LINQ的expression tree比IL高级,组装起来也方便许多。假如做出一个什么InjectionCodeBuilder之类的,接受expression tree为参数的话,就既能照顾到编译时的lambda expression,也能照顾到运行时自行组装的expression tree。调用一个现成的Compile()方法就能编译为IL,何乐而不为呢。
P.S. 说到AOP,我不是不知道PostSharp……不过它在内部到底是怎么实现的我还没看清楚。这库的代码量也不小啊(晕乎
PostSharp Core里的code model和weaver大概是值得关注的点吧。
总之自己要是能做一个不同的AOP实现的话,总也是件有趣的事 ^ ^
评论
5 楼
hd700
2008-06-14
写的不错,我发现javaeye里研究的东西比博客园研究的要深入也有意思。希望博主再接再厉以每星期1篇的速度来写这个系列。
postsharp确实挺强大的,也期待博主对这个东西实现的深入分析
postsharp确实挺强大的,也期待博主对这个东西实现的深入分析
4 楼
Lighting
2008-04-16
嗯……我也得休息一下了……大四估计也没时间再搞汉化的了……XD……等Akito搞完FA就神隐去
3 楼
RednaxelaFX
2008-04-16
哟,明大~期待一下明大什么时候也写点blog交流下~~
话说这七色也做完了,暑假之前我也不会再接汉化了,呼……
话说这七色也做完了,暑假之前我也不会再接汉化了,呼……
2 楼
Lighting
2008-04-15
哈……看了半天还是不懂……
~~注册了个ID第一个帖在这里水了~~
~~注册了个ID第一个帖在这里水了~~
1 楼
ray_linn
2008-04-15
哈,早上头脑不清醒,看了半天没明白。现在重新看过,有所启发。
我找到代码中实现Emit IL的功能,即Emit " IL Text String",可以用高级点(也就只是汇编级)来插入IL。如果二者结合起来,似乎可以实现IL抽取和IL注射(我不太确定)。
可以继续讨论,应该是个很有意思的东西。我也正在看PostSharp和Rail(不是ruby那个rail)
我找到代码中实现Emit IL的功能,即Emit " IL Text String",可以用高级点(也就只是汇编级)来插入IL。如果二者结合起来,似乎可以实现IL抽取和IL注射(我不太确定)。
可以继续讨论,应该是个很有意思的东西。我也正在看PostSharp和Rail(不是ruby那个rail)
发表评论
-
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22388(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
对象的重量
2011-08-21 17:15 0http://domino.research.ibm.com/ ... -
GetCustomAttribute()每次都返回新Attribute实例
2009-11-10 10:30 0Jeffrey Zhao: 一次失败的尝试(上):原来GetC ... -
委托与方法和隐藏参数
2009-09-07 15:32 3304之前正好发了些帖子是关于CLR里的委托的,然后看到老赵说事件也 ... -
要让CLR挂掉的话(第二弹)……
2009-09-04 03:26 12870(Disclaimer:如果需要转 ... -
要让CLR挂掉的话……
2009-09-02 16:53 4775(Disclaimer:如果需要转载请先与我联系。 作者:Re ... -
趣味编程:函数式链表的快速排序
2009-08-31 08:53 3444(恢复自2009-08-28的备份 ... -
事件处理器导致内存泄漏
2009-08-25 15:03 0Memory leak via event handlers ... -
C# 3.0的类型推导
2009-08-23 12:24 0Howard Dierking: Lambda, Lambda ... -
把lock的意思给弄混了 T T
2009-08-20 17:49 2597悲剧啊……前几天有个同学不停问我Java里的同步问题,今天写C ... -
把IEnumerable<T>和IObservable<T>粘起来?
2009-07-23 03:02 0Channel 9: Expert to Expert: Br ... -
Scott Peterson: Variance, Thy Name is Ambiguity
2009-07-01 23:49 1634原文作者:Scott Peterson 原文地址:http:/ ... -
void无法协变
2009-06-30 11:17 0Eric Lippert The void is invari ... -
同一个表达式算出来的浮点数结果会不相等?
2009-05-30 03:27 0浮点数有很多可把玩的地方。例如下面这段C程序: #includ ... -
C#开始默认引用Microsoft.CSharp.dll
2009-05-20 16:14 0记得VB6的运行时么?留意到VB.NET的程序都需要额外的VB ... -
反射与显式实现接口的方法
2009-05-20 11:43 4055在前一帖里,我用到了下面三处Expression.Call() ... -
看到一个关于ref参数与多态的问题,记一下
2009-05-18 10:48 1940刚才读到Alan McGovern的一帖,问为什么形式参数是r ... -
C#的+=运算符两例
2009-05-06 18:18 2031刚偶尔看到了justjavac写的java解惑 - 半斤八两( ...
相关推荐
如果函数是通过非Lambda方式调用,例如`myAction(5, "Hello")`,则需要使用`MethodInfo`和`ParameterInfo`来获取参数信息,但这无法直接获取到参数值,因为值是在运行时提供的,而不是在代码中硬编码。 总结一下,...
# 题目:使用lambda来创建匿名函数。
在事件处理中,我们可以使用 Lambda 表达式来简化事件处理代码: ```csharp button.Click += (sender, e) => { Console.WriteLine("Button clicked!"); }; ``` Lambda 表达式是 C# 编程语言中的一个非常重要的概念...
在C#中,我们可以使用`IQueryable<T>`接口的扩展方法来构建这些查询,这些方法在内部会将Lambda表达式转换为表达式树(Expression Tree)。 表达式树是.NET框架中的一种类型,表示可执行的代码的抽象语法树。它们是...
3. **编译表达式**:使用`Expression.Lambda`创建一个Lambda表达式,并通过`Compile`方法将其编译为可执行的`Delegate`。 4. **执行查询**:最后,使用编译后的委托对数据集进行查询。这样,即使在编译时未知查询...
这个过程通常需要使用到Python的`eval()`函数或`exec()`函数,但这两个函数在安全性上存在风险,因为它们会执行传入的代码,可能导致代码注入攻击。因此,更安全的做法是使用`ast`(抽象语法树)模块来解析字符串,...
lambda 使用详解 lambda 表达式是 Java8 中的一种新特性,它可以极大地减少代码冗余,同时也可以提高代码的可读性。它可以配合 Java8 的 Stream API,将业务功能通过函数式编程简洁的实现。 lambda 表达式的语法有...
本文将深入探讨如何使用Lambda表达式来查找指定字符,以及其背后的原理和应用场景。 Lambda表达式在C#中的基本语法形式是 `(parameters) => expression`,其中`parameters`代表输入参数,`expression`是基于这些...
本篇文章将深入探讨如何利用lambda表达式来获取key,并将list转换为dict,这是一种常见的数据结构转换技巧。 首先,lambda表达式是Python中的一种简短的匿名函数定义方式。它的一般形式是`lambda arguments: ...
标题 "Go-运行标准Go代码在AWSLambda平台中" 指向了使用Go语言在亚马逊AWS Lambda服务上部署无服务器应用的主题。AWS Lambda是一种计算服务,它允许开发者运行代码而无需预先配置或管理服务器。这里,我们关注的是...
这段代码使用了Lambda表达式来构建查询条件,其中`User::getUsername`是Lambda语法,用于指定`username`字段。然而,问题可能出现在实体类`User`的定义上。 为了确保MyBatis-Plus能够正确地映射Java字段到数据库列...
我们可以使用`new`关键字和方法名来实例化一个Delegate对象,或者使用lambda表达式。以下是如何关联一个方法到Delegate实例的例子: ```csharp public class MyClass { public void MyMethod(string message) {...
在C++中,Lambda函数是一种特殊的匿名函数,它使得开发者能够在代码中的任何地方快速定义小块的代码,并将其作为参数传递,或直接作为函数调用。Lambda函数通常被用于需要函数对象的场景,比如在STL算法中。这种函数...
Lambda表达式的形式为:`(parameters) -> expression`,其中`parameters`是函数参数,`->`是箭头符号,表示参数列表与函数体的分隔,`expression`是函数体,可以是单行代码或一个代码块。 2. **Lambda表达式的使用...
在上面的代码中,我们使用一个 Lambda 表达式来实现 Runnable 接口,然后使用这个 Lambda 表达式来打印 "Hello, World!"。 Lambda 表达式是 Java 语言中的一种函数式编程特性,允许将简单的函数作为操作传递给方法...
本文实例讲述了C#使用委托(delegate)实现在两个form之间传递数据的方法。分享给大家供大家参考。具体分析如下: 关于Delegate【代理、委托】是C#中一个非常重要的概念,向前可以推演到C++的指针,向后可以延续到匿名...
现在,我们可以用lambda简化这些代码。 - **函数式编程**:Java 8引入了`java.util.Function`等接口,以及`Stream API`,允许开发者使用lambda表达式进行函数式编程,如映射、过滤、聚合等操作。 4. **并行处理**...
1、Lambda表达式概述:了解Lambda表达式的定义、语法和变量捕获机制,以及为什么要在Java中引入Lambda表达式来支持函数式编程。 2、函数式接口与Lambda表达式:学习如何使用Lambda表达式与不同类型的函数式接口进行...
总的来说,“java8lambda表达式Demo”提供了一个很好的学习资源,帮助开发者理解如何在Android环境中有效地利用Java 8的Lambda表达式。通过研究这个Demo,你可以深入了解Lambda表达式如何简化代码,提高生产力,并为...
[WTL/ATL]_[初级]_[DispatchAsync使用lambda表达式来简化发送数据到界面线程] 博客内容对应的项目 https://infoworld.blog.csdn.net/article/details/105653177。使用vs2017+wtl,工作线程发送数据到主线程的例子,...