| @@ -0,0 +1,16 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.ComponentModel; | |||
| using System.Linq; | |||
| using System.Text; | |||
| namespace EmitCreateDynamicProxy | |||
| { | |||
| class DDD : INotifyPropertyChanged | |||
| { | |||
| public event PropertyChangedEventHandler PropertyChanged; | |||
| public string Name { get => _Name; set { _Name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("uuu")); } } | |||
| private string _Name = ""; | |||
| } | |||
| } | |||
| @@ -0,0 +1,228 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.ComponentModel; | |||
| using System.Linq; | |||
| using System.Reflection; | |||
| using System.Reflection.Emit; | |||
| using System.Text; | |||
| using System.Threading; | |||
| namespace EmitCreateDynamicProxy | |||
| { | |||
| public class DynamicProxyGenerator | |||
| { | |||
| private const string DynamicAssemblyName = "DynamicAssembly";//动态程序集名称 | |||
| private const string DynamicModuleName = "DynamicAssemblyModule"; | |||
| private const string DynamicModuleDllName = "DynamicAssembly.dll";//动态模块名称 | |||
| private const string ProxyClassNameFormater = "{0}Proxy"; | |||
| private const string ModifiedPropertyNamesFieldName = "ModifiedPropertyNames"; | |||
| private const MethodAttributes GetSetMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.CheckAccessOnOverride | MethodAttributes.Virtual | MethodAttributes.HideBySig; | |||
| /// <summary> | |||
| /// 创建动态程序集,返回AssemblyBuilder | |||
| /// </summary> | |||
| /// <param name="isSavaDll"></param> | |||
| /// <returns></returns> | |||
| private static AssemblyBuilder DefineDynamicAssembly(bool isSavaDll = false) | |||
| { | |||
| //动态创建程序集 | |||
| AssemblyName DemoName = new AssemblyName(DynamicAssemblyName); | |||
| AssemblyBuilderAccess assemblyBuilderAccess = isSavaDll ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run; | |||
| AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, assemblyBuilderAccess); | |||
| return dynamicAssembly; | |||
| } | |||
| /// <summary> | |||
| /// 创建动态模块,返回ModuleBuilder | |||
| /// </summary> | |||
| /// <param name="isSavaDll"></param> | |||
| /// <returns>ModuleBuilder</returns> | |||
| private static ModuleBuilder DefineDynamicModule(AssemblyBuilder dynamicAssembly, bool isSavaDll = false) | |||
| { | |||
| ModuleBuilder moduleBuilder = null; | |||
| //动态创建模块 | |||
| if (isSavaDll) | |||
| moduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName, DynamicModuleDllName); | |||
| else | |||
| moduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName); | |||
| return moduleBuilder; | |||
| } | |||
| /// <summary> | |||
| /// 创建动态代理类,重写属性Get Set 方法,并监控属性的Set方法,把变更的属性名加入到list集合中,需要监控的属性必须是virtual | |||
| /// 如果你想保存修改的属性名和属性值,修改Set方法的IL实现 | |||
| /// </summary> | |||
| /// <typeparam name="T"></typeparam> | |||
| /// <param name="isSavaDynamicModule"></param> | |||
| /// <returns></returns> | |||
| public static T CreateDynamicProxy<T>(bool isSavaDynamicModule = false) | |||
| { | |||
| Type modifiedPropertyNamesType = typeof(HashSet<string>); | |||
| Type typeNeedProxy = typeof(T); | |||
| AssemblyBuilder assemblyBuilder = DefineDynamicAssembly(isSavaDynamicModule); | |||
| //动态创建模块 | |||
| ModuleBuilder moduleBuilder = DefineDynamicModule(assemblyBuilder, isSavaDynamicModule); | |||
| string proxyClassName = string.Format(ProxyClassNameFormater, typeNeedProxy.Name); | |||
| //动态创建类代理 | |||
| TypeBuilder typeBuilderProxy = moduleBuilder.DefineType(proxyClassName, TypeAttributes.Public, typeNeedProxy); | |||
| //定义一个变量存放属性变更名 | |||
| FieldBuilder fbModifiedPropertyNames = typeBuilderProxy.DefineField(ModifiedPropertyNamesFieldName, modifiedPropertyNamesType, FieldAttributes.Public); | |||
| //定义接口 | |||
| var pt = typeof(PropertyChangedEventHandler); | |||
| typeBuilderProxy.AddInterfaceImplementation(typeof(INotifyPropertyChanged)); | |||
| var eil = typeBuilderProxy.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler)); | |||
| //add field | |||
| var eb = typeBuilderProxy.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private); | |||
| var compareExchange = GetGenericMethod(typeof(Interlocked), "CompareExchange");// finds the correct method to call. | |||
| // thanks to @marc, create the specific method with the correct type | |||
| compareExchange = compareExchange.MakeGenericMethod(typeof(PropertyChangedEventHandler)); | |||
| //add methoed | |||
| var mas = MethodAttributes.Public | MethodAttributes.HideBySig | |||
| | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.Final; | |||
| var mb = typeBuilderProxy.DefineMethod("add_PropertyChanged", mas, typeof(void), new Type[] { pt }); | |||
| mb.DefineParameter(0, ParameterAttributes.Retval, null); | |||
| mb.DefineParameter(1, ParameterAttributes.In, "value"); | |||
| var il = mb.GetILGenerator(); | |||
| il.DeclareLocal(pt); | |||
| il.DeclareLocal(pt); | |||
| il.DeclareLocal(pt); | |||
| il.Emit(OpCodes.Ldarg_0); | |||
| il.Emit(OpCodes.Ldfld, eb); | |||
| il.Emit(OpCodes.Stloc_0); | |||
| var lable = il.DefineLabel(); | |||
| il.MarkLabel(lable); | |||
| il.Emit(OpCodes.Ldloc_0); | |||
| il.Emit(OpCodes.Stloc_1); | |||
| il.Emit(OpCodes.Ldloc_1); | |||
| il.Emit(OpCodes.Ldarg_1); | |||
| il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new Type[] { typeof(Delegate), typeof(Delegate) })); | |||
| il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler)); | |||
| il.Emit(OpCodes.Stloc_2); | |||
| il.Emit(OpCodes.Ldarg_0); | |||
| il.Emit(OpCodes.Ldflda, eb); | |||
| il.Emit(OpCodes.Ldloc_2); | |||
| il.Emit(OpCodes.Ldloc_1); | |||
| il.Emit(OpCodes.Call, compareExchange); | |||
| il.Emit(OpCodes.Stloc_0); | |||
| il.Emit(OpCodes.Ldloc_0); | |||
| il.Emit(OpCodes.Ldloc_1); | |||
| il.Emit(OpCodes.Bne_Un_S, lable); | |||
| il.Emit(OpCodes.Ret); | |||
| //remove event | |||
| mb = typeBuilderProxy.DefineMethod("remove_PropertyChanged", mas, typeof(void), new Type[] { pt }); | |||
| mb.DefineParameter(0, ParameterAttributes.Retval, null); | |||
| mb.DefineParameter(1, ParameterAttributes.In, "value"); | |||
| il = mb.GetILGenerator(); | |||
| il.DeclareLocal(pt); | |||
| il.DeclareLocal(pt); | |||
| il.DeclareLocal(pt); | |||
| il.Emit(OpCodes.Ldarg_0); | |||
| il.Emit(OpCodes.Ldfld, eb); | |||
| il.Emit(OpCodes.Stloc_0); | |||
| lable = il.DefineLabel(); | |||
| il.MarkLabel(lable); | |||
| il.Emit(OpCodes.Ldloc_0); | |||
| il.Emit(OpCodes.Stloc_1); | |||
| il.Emit(OpCodes.Ldloc_1); | |||
| il.Emit(OpCodes.Ldarg_1); | |||
| il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new Type[] { typeof(Delegate), typeof(Delegate) })); | |||
| il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler)); | |||
| il.Emit(OpCodes.Stloc_2); | |||
| il.Emit(OpCodes.Ldarg_0); | |||
| il.Emit(OpCodes.Ldflda, eb); | |||
| il.Emit(OpCodes.Ldloc_2); | |||
| il.Emit(OpCodes.Ldloc_1); | |||
| il.Emit(OpCodes.Call, compareExchange); | |||
| il.Emit(OpCodes.Stloc_0); | |||
| il.Emit(OpCodes.Ldloc_0); | |||
| il.Emit(OpCodes.Ldloc_1); | |||
| il.Emit(OpCodes.Bne_Un_S, lable); | |||
| il.Emit(OpCodes.Ret); | |||
| /* | |||
| * 构造函数 实例化 ModifiedPropertyNames,生成类似于下面的代码 | |||
| ModifiedPropertyNames = new List<string>(); | |||
| */ | |||
| ConstructorBuilder constructorBuilder = typeBuilderProxy.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null); | |||
| ILGenerator ilgCtor = constructorBuilder.GetILGenerator(); | |||
| ilgCtor.Emit(OpCodes.Ldarg_0);//加载当前类 | |||
| ilgCtor.Emit(OpCodes.Newobj, modifiedPropertyNamesType.GetConstructor(new Type[0]));//实例化对象入栈 | |||
| ilgCtor.Emit(OpCodes.Stfld, fbModifiedPropertyNames);//设置fbModifiedPropertyNames值,为刚入栈的实例化对象 | |||
| ilgCtor.Emit(OpCodes.Ret);//返回 | |||
| //获取被代理对象的所有属性,循环属性进行重写 | |||
| PropertyInfo[] properties = typeNeedProxy.GetProperties(); | |||
| foreach (PropertyInfo propertyInfo in properties) | |||
| { | |||
| string propertyName = propertyInfo.Name; | |||
| Type typePepropertyInfo = propertyInfo.PropertyType; | |||
| //动态创建字段和属性 | |||
| FieldBuilder fieldBuilder = typeBuilderProxy.DefineField("_" + propertyName, typePepropertyInfo, FieldAttributes.Private); | |||
| PropertyBuilder propertyBuilder = typeBuilderProxy.DefineProperty(propertyName, PropertyAttributes.SpecialName, typePepropertyInfo, null); | |||
| //重写属性的Get Set方法 | |||
| var methodGet = typeBuilderProxy.DefineMethod("get_" + propertyName, GetSetMethodAttributes, typePepropertyInfo, Type.EmptyTypes); | |||
| var methodSet = typeBuilderProxy.DefineMethod("set_" + propertyName, GetSetMethodAttributes, null, new Type[] { typePepropertyInfo }); | |||
| //il of get method | |||
| var ilGetMethod = methodGet.GetILGenerator(); | |||
| ilGetMethod.Emit(OpCodes.Ldarg_0); | |||
| ilGetMethod.Emit(OpCodes.Ldfld, fieldBuilder); | |||
| ilGetMethod.Emit(OpCodes.Ret); | |||
| //il of set method | |||
| ILGenerator ilSetMethod = methodSet.GetILGenerator(); | |||
| ilSetMethod.Emit(OpCodes.Ldarg_0); | |||
| ilSetMethod.Emit(OpCodes.Ldarg_1); | |||
| ilSetMethod.Emit(OpCodes.Stfld, fieldBuilder); | |||
| ilSetMethod.Emit(OpCodes.Ldarg_0); | |||
| ilSetMethod.Emit(OpCodes.Ldfld, fbModifiedPropertyNames); | |||
| ilSetMethod.Emit(OpCodes.Ldstr, propertyInfo.Name); | |||
| ilSetMethod.Emit(OpCodes.Callvirt, modifiedPropertyNamesType.GetMethod("Add", new Type[] { typeof(string) })); | |||
| ilSetMethod.Emit(OpCodes.Pop); | |||
| ilSetMethod.Emit(OpCodes.Ret); | |||
| //设置属性的Get Set方法 | |||
| propertyBuilder.SetGetMethod(methodGet); | |||
| propertyBuilder.SetSetMethod(methodSet); | |||
| } | |||
| //使用动态类创建类型 | |||
| Type proxyClassType = typeBuilderProxy.CreateType(); | |||
| //保存动态创建的程序集 | |||
| if (isSavaDynamicModule) | |||
| assemblyBuilder.Save(DynamicModuleDllName); | |||
| //创建类实例 | |||
| var instance = Activator.CreateInstance(proxyClassType); | |||
| return (T)instance; | |||
| } | |||
| /// <summary> | |||
| /// 获取属性的变更名称, | |||
| /// 此处只检测调用了Set方法的属性,不会检测值是否真的有变 | |||
| /// </summary> | |||
| /// <param name="obj"></param> | |||
| /// <returns></returns> | |||
| public static HashSet<string> GetModifiedProperties(object obj) | |||
| { | |||
| FieldInfo fieldInfo = obj.GetType().GetField(ModifiedPropertyNamesFieldName); | |||
| if (fieldInfo == null) return null; | |||
| object value = fieldInfo.GetValue(obj); | |||
| return value as HashSet<string>; | |||
| } | |||
| private static MethodInfo GetGenericMethod(Type type, string methodName) | |||
| { | |||
| var q = from m in type.GetMethods() | |||
| where m.Name == methodName && m.IsGenericMethod | |||
| select m; | |||
| return q.FirstOrDefault(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,60 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
| <PropertyGroup> | |||
| <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||
| <Platform Condition=" '$(Platform)' == '' ">x86</Platform> | |||
| <ProductVersion>8.0.30703</ProductVersion> | |||
| <SchemaVersion>2.0</SchemaVersion> | |||
| <ProjectGuid>{BDA6268A-ADF2-4DA3-8053-81CA4AD007B0}</ProjectGuid> | |||
| <OutputType>Exe</OutputType> | |||
| <AppDesignerFolder>Properties</AppDesignerFolder> | |||
| <RootNamespace>EmitCreateDynamicProxy</RootNamespace> | |||
| <AssemblyName>EmitCreateDynamicProxy</AssemblyName> | |||
| <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> | |||
| <TargetFrameworkProfile>Client</TargetFrameworkProfile> | |||
| <FileAlignment>512</FileAlignment> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> | |||
| <PlatformTarget>x86</PlatformTarget> | |||
| <DebugSymbols>true</DebugSymbols> | |||
| <DebugType>full</DebugType> | |||
| <Optimize>false</Optimize> | |||
| <OutputPath>bin\Debug\</OutputPath> | |||
| <DefineConstants>DEBUG;TRACE</DefineConstants> | |||
| <ErrorReport>prompt</ErrorReport> | |||
| <WarningLevel>4</WarningLevel> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> | |||
| <PlatformTarget>x86</PlatformTarget> | |||
| <DebugType>pdbonly</DebugType> | |||
| <Optimize>true</Optimize> | |||
| <OutputPath>bin\Release\</OutputPath> | |||
| <DefineConstants>TRACE</DefineConstants> | |||
| <ErrorReport>prompt</ErrorReport> | |||
| <WarningLevel>4</WarningLevel> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <Reference Include="System" /> | |||
| <Reference Include="System.Core" /> | |||
| <Reference Include="System.Xml.Linq" /> | |||
| <Reference Include="System.Data.DataSetExtensions" /> | |||
| <Reference Include="Microsoft.CSharp" /> | |||
| <Reference Include="System.Data" /> | |||
| <Reference Include="System.Xml" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <Compile Include="DDD.cs" /> | |||
| <Compile Include="DynamicProxyGenerator.cs" /> | |||
| <Compile Include="Model.cs" /> | |||
| <Compile Include="Program.cs" /> | |||
| <Compile Include="Properties\AssemblyInfo.cs" /> | |||
| </ItemGroup> | |||
| <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
| <!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||
| Other similar extension points exist, see Microsoft.Common.targets. | |||
| <Target Name="BeforeBuild"> | |||
| </Target> | |||
| <Target Name="AfterBuild"> | |||
| </Target> | |||
| --> | |||
| </Project> | |||
| @@ -0,0 +1,14 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| namespace EmitCreateDynamicProxy | |||
| { | |||
| public class Model | |||
| { | |||
| public virtual string LoginName { get; set; } | |||
| public virtual string Password { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,153 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Reflection; | |||
| using System.Reflection.Emit; | |||
| namespace EmitCreateDynamicProxy | |||
| { | |||
| class Program | |||
| { | |||
| static void Main(string[] args) | |||
| { | |||
| //var command = Proxy.Of<Command>(); | |||
| //command.Execute(); | |||
| //Console.WriteLine("Hi, Dennis, great, we got the interceptor works."); | |||
| //Console.ReadLine(); | |||
| Model m = DynamicProxyGenerator.CreateDynamicProxy<Model>(true); | |||
| m.LoginName = "ddd"; | |||
| HashSet<string> modifiedPropertyNames = DynamicProxyGenerator.GetModifiedProperties(m) as HashSet<string>; | |||
| } | |||
| } | |||
| public class Command | |||
| { | |||
| public virtual void Execute() | |||
| { | |||
| Console.WriteLine("Command executing..."); | |||
| Console.WriteLine("Hello Kitty!"); | |||
| Console.WriteLine("Command executed."); | |||
| } | |||
| } | |||
| public class Interceptor | |||
| { | |||
| public object Invoke(object @object, string @method, object[] parameters) | |||
| { | |||
| Console.WriteLine( | |||
| string.Format("Interceptor does something before invoke [{0}]...", @method)); | |||
| var retObj = @object.GetType().GetMethod(@method).Invoke(@object, parameters); | |||
| Console.WriteLine( | |||
| string.Format("Interceptor does something after invoke [{0}]...", @method)); | |||
| return retObj; | |||
| } | |||
| } | |||
| public class Proxy | |||
| { | |||
| public static T Of<T>() where T : class, new() | |||
| { | |||
| string nameOfAssembly = typeof(T).Name + "ProxyAssembly"; | |||
| string nameOfModule = typeof(T).Name + "ProxyModule"; | |||
| string nameOfType = typeof(T).Name + "Proxy"; | |||
| var assemblyName = new AssemblyName(nameOfAssembly); | |||
| var assembly = AppDomain.CurrentDomain | |||
| .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); | |||
| var moduleBuilder = assembly.DefineDynamicModule(nameOfModule); | |||
| var typeBuilder = moduleBuilder.DefineType( | |||
| nameOfType, TypeAttributes.Public, typeof(T)); | |||
| InjectInterceptor<T>(typeBuilder); | |||
| var t = typeBuilder.CreateType(); | |||
| return Activator.CreateInstance(t) as T; | |||
| } | |||
| private static void InjectInterceptor<T>(TypeBuilder typeBuilder) | |||
| { | |||
| // ---- define fields ---- | |||
| var fieldInterceptor = typeBuilder.DefineField( | |||
| "_interceptor", typeof(Interceptor), FieldAttributes.Private); | |||
| // ---- define costructors ---- | |||
| var constructorBuilder = typeBuilder.DefineConstructor( | |||
| MethodAttributes.Public, CallingConventions.Standard, null); | |||
| var ilOfCtor = constructorBuilder.GetILGenerator(); | |||
| ilOfCtor.Emit(OpCodes.Ldarg_0); | |||
| ilOfCtor.Emit(OpCodes.Newobj, typeof(Interceptor).GetConstructor(new Type[0])); | |||
| ilOfCtor.Emit(OpCodes.Stfld, fieldInterceptor); | |||
| ilOfCtor.Emit(OpCodes.Ret); | |||
| // ---- define methods ---- | |||
| var methodsOfType = typeof(T).GetMethods(BindingFlags.Public | BindingFlags.Instance); | |||
| for (var i = 0; i < methodsOfType.Length; i++) | |||
| { | |||
| var method = methodsOfType[i]; | |||
| var methodParameterTypes = | |||
| method.GetParameters().Select(p => p.ParameterType).ToArray(); | |||
| var methodBuilder = typeBuilder.DefineMethod( | |||
| method.Name, | |||
| MethodAttributes.Public | MethodAttributes.Virtual, | |||
| CallingConventions.Standard, | |||
| method.ReturnType, | |||
| methodParameterTypes); | |||
| var ilOfMethod = methodBuilder.GetILGenerator(); | |||
| ilOfMethod.Emit(OpCodes.Ldarg_0); | |||
| ilOfMethod.Emit(OpCodes.Ldfld, fieldInterceptor); | |||
| // create instance of T | |||
| ilOfMethod.Emit(OpCodes.Newobj, typeof(T).GetConstructor(new Type[0])); | |||
| ilOfMethod.Emit(OpCodes.Ldstr, method.Name); | |||
| // build the method parameters | |||
| if (methodParameterTypes == null) | |||
| { | |||
| ilOfMethod.Emit(OpCodes.Ldnull); | |||
| } | |||
| else | |||
| { | |||
| var parameters = ilOfMethod.DeclareLocal(typeof(object[])); | |||
| ilOfMethod.Emit(OpCodes.Ldc_I4, methodParameterTypes.Length); | |||
| ilOfMethod.Emit(OpCodes.Newarr, typeof(object)); | |||
| ilOfMethod.Emit(OpCodes.Stloc, parameters); | |||
| for (var j = 0; j < methodParameterTypes.Length; j++) | |||
| { | |||
| ilOfMethod.Emit(OpCodes.Ldloc, parameters); | |||
| ilOfMethod.Emit(OpCodes.Ldc_I4, j); | |||
| ilOfMethod.Emit(OpCodes.Ldarg, j + 1); | |||
| ilOfMethod.Emit(OpCodes.Stelem_Ref); | |||
| } | |||
| ilOfMethod.Emit(OpCodes.Ldloc, parameters); | |||
| } | |||
| // call Invoke() method of Interceptor | |||
| ilOfMethod.Emit(OpCodes.Callvirt, typeof(Interceptor).GetMethod("Invoke")); | |||
| // pop the stack if return void | |||
| if (method.ReturnType == typeof(void)) | |||
| { | |||
| ilOfMethod.Emit(OpCodes.Pop); | |||
| } | |||
| // complete | |||
| ilOfMethod.Emit(OpCodes.Ret); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| using System.Reflection; | |||
| using System.Runtime.CompilerServices; | |||
| using System.Runtime.InteropServices; | |||
| // General Information about an assembly is controlled through the following | |||
| // set of attributes. Change these attribute values to modify the information | |||
| // associated with an assembly. | |||
| [assembly: AssemblyTitle("EmitCreateDynamicProxy")] | |||
| [assembly: AssemblyDescription("")] | |||
| [assembly: AssemblyConfiguration("")] | |||
| [assembly: AssemblyCompany("")] | |||
| [assembly: AssemblyProduct("EmitCreateDynamicProxy")] | |||
| [assembly: AssemblyCopyright("Copyright © 2013")] | |||
| [assembly: AssemblyTrademark("")] | |||
| [assembly: AssemblyCulture("")] | |||
| // Setting ComVisible to false makes the types in this assembly not visible | |||
| // to COM components. If you need to access a type in this assembly from | |||
| // COM, set the ComVisible attribute to true on that type. | |||
| [assembly: ComVisible(false)] | |||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | |||
| [assembly: Guid("7dbdf814-4cbd-4fc1-987f-976261539900")] | |||
| // Version information for an assembly consists of the following four values: | |||
| // | |||
| // Major Version | |||
| // Minor Version | |||
| // Build Number | |||
| // Revision | |||
| // | |||
| // You can specify all the values or you can default the Build and Revision Numbers | |||
| // by using the '*' as shown below: | |||
| // [assembly: AssemblyVersion("1.0.*")] | |||
| [assembly: AssemblyVersion("1.0.0.0")] | |||
| [assembly: AssemblyFileVersion("1.0.0.0")] | |||
| @@ -0,0 +1,57 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
| <PropertyGroup> | |||
| <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||
| <Platform Condition=" '$(Platform)' == '' ">x86</Platform> | |||
| <ProductVersion>8.0.30703</ProductVersion> | |||
| <SchemaVersion>2.0</SchemaVersion> | |||
| <ProjectGuid>{C4DFB7F2-8C56-4036-B4FF-E56B456B3943}</ProjectGuid> | |||
| <OutputType>Exe</OutputType> | |||
| <AppDesignerFolder>Properties</AppDesignerFolder> | |||
| <RootNamespace>EmitCreateMembers</RootNamespace> | |||
| <AssemblyName>EmitCreateMembers</AssemblyName> | |||
| <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> | |||
| <TargetFrameworkProfile>Client</TargetFrameworkProfile> | |||
| <FileAlignment>512</FileAlignment> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> | |||
| <PlatformTarget>x86</PlatformTarget> | |||
| <DebugSymbols>true</DebugSymbols> | |||
| <DebugType>full</DebugType> | |||
| <Optimize>false</Optimize> | |||
| <OutputPath>bin\Debug\</OutputPath> | |||
| <DefineConstants>DEBUG;TRACE</DefineConstants> | |||
| <ErrorReport>prompt</ErrorReport> | |||
| <WarningLevel>4</WarningLevel> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> | |||
| <PlatformTarget>x86</PlatformTarget> | |||
| <DebugType>pdbonly</DebugType> | |||
| <Optimize>true</Optimize> | |||
| <OutputPath>bin\Release\</OutputPath> | |||
| <DefineConstants>TRACE</DefineConstants> | |||
| <ErrorReport>prompt</ErrorReport> | |||
| <WarningLevel>4</WarningLevel> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <Reference Include="System" /> | |||
| <Reference Include="System.Core" /> | |||
| <Reference Include="System.Xml.Linq" /> | |||
| <Reference Include="System.Data.DataSetExtensions" /> | |||
| <Reference Include="Microsoft.CSharp" /> | |||
| <Reference Include="System.Data" /> | |||
| <Reference Include="System.Xml" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <Compile Include="Program.cs" /> | |||
| <Compile Include="Properties\AssemblyInfo.cs" /> | |||
| </ItemGroup> | |||
| <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
| <!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||
| Other similar extension points exist, see Microsoft.Common.targets. | |||
| <Target Name="BeforeBuild"> | |||
| </Target> | |||
| <Target Name="AfterBuild"> | |||
| </Target> | |||
| --> | |||
| </Project> | |||
| @@ -0,0 +1,138 @@ | |||
| using System; | |||
| using System.Reflection; | |||
| using System.Reflection.Emit; | |||
| namespace EmitCreateMembers | |||
| { | |||
| class Program | |||
| { | |||
| static void Main(string[] args) | |||
| { | |||
| // specify a new assembly name | |||
| var assemblyName = new AssemblyName("Pets"); | |||
| // create assembly builder | |||
| var assemblyBuilder = AppDomain.CurrentDomain | |||
| .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); | |||
| // create module builder | |||
| var moduleBuilder = assemblyBuilder.DefineDynamicModule("PetsModule", "Pets.dll"); | |||
| // create type builder for a class | |||
| var typeBuilder = moduleBuilder.DefineType("Kitty", TypeAttributes.Public); | |||
| // then create whole class structure | |||
| CreateKittyClassStructure(typeBuilder); | |||
| // then create the whole class type | |||
| var classType = typeBuilder.CreateType(); | |||
| // save assembly | |||
| assemblyBuilder.Save("Pets.dll"); | |||
| Console.WriteLine("Hi, Dennis, a Pets assembly has been generated for you."); | |||
| Console.ReadLine(); | |||
| } | |||
| private static void CreateKittyClassStructure(TypeBuilder typeBuilder) | |||
| { | |||
| // ---- define fields ---- | |||
| var fieldId = typeBuilder.DefineField( | |||
| "_id", typeof(int), FieldAttributes.Private); | |||
| var fieldName = typeBuilder.DefineField( | |||
| "_name", typeof(string), FieldAttributes.Private); | |||
| // ---- define costructors ---- | |||
| Type objType = Type.GetType("System.Object"); | |||
| ConstructorInfo objCtor = objType.GetConstructor(new Type[0]); | |||
| Type[] constructorArgs = { typeof(int), typeof(string) }; | |||
| var constructorBuilder = typeBuilder.DefineConstructor( | |||
| MethodAttributes.Public, CallingConventions.Standard, constructorArgs); | |||
| ILGenerator ilOfCtor = constructorBuilder.GetILGenerator(); | |||
| ilOfCtor.Emit(OpCodes.Ldarg_0); | |||
| ilOfCtor.Emit(OpCodes.Call, objCtor); | |||
| ilOfCtor.Emit(OpCodes.Ldarg_0); | |||
| ilOfCtor.Emit(OpCodes.Ldarg_1); | |||
| ilOfCtor.Emit(OpCodes.Stfld, fieldId); | |||
| ilOfCtor.Emit(OpCodes.Ldarg_0); | |||
| ilOfCtor.Emit(OpCodes.Ldarg_2); | |||
| ilOfCtor.Emit(OpCodes.Stfld, fieldName); | |||
| ilOfCtor.Emit(OpCodes.Ret); | |||
| // ---- define properties ---- | |||
| var methodGetId = typeBuilder.DefineMethod( | |||
| "GetId", MethodAttributes.Public, typeof(int), null); | |||
| var methodSetId = typeBuilder.DefineMethod( | |||
| "SetId", MethodAttributes.Public, null, new Type[] { typeof(int) }); | |||
| var ilOfGetId = methodGetId.GetILGenerator(); | |||
| ilOfGetId.Emit(OpCodes.Ldarg_0); // this | |||
| ilOfGetId.Emit(OpCodes.Ldfld, fieldId); | |||
| ilOfGetId.Emit(OpCodes.Ret); | |||
| var ilOfSetId = methodSetId.GetILGenerator(); | |||
| ilOfSetId.Emit(OpCodes.Ldarg_0); // this | |||
| ilOfSetId.Emit(OpCodes.Ldarg_1); // the first one in arguments list | |||
| ilOfSetId.Emit(OpCodes.Stfld, fieldId); | |||
| ilOfSetId.Emit(OpCodes.Ret); | |||
| // create Id property | |||
| var propertyId = typeBuilder.DefineProperty( | |||
| "Id", PropertyAttributes.None, typeof(int), null); | |||
| propertyId.SetGetMethod(methodGetId); | |||
| propertyId.SetSetMethod(methodSetId); | |||
| var methodGetName = typeBuilder.DefineMethod( | |||
| "GetName", MethodAttributes.Public, typeof(string), null); | |||
| var methodSetName = typeBuilder.DefineMethod( | |||
| "SetName", MethodAttributes.Public, null, new Type[] { typeof(string) }); | |||
| var ilOfGetName = methodGetName.GetILGenerator(); | |||
| ilOfGetName.Emit(OpCodes.Ldarg_0); // this | |||
| ilOfGetName.Emit(OpCodes.Ldfld, fieldName); | |||
| ilOfGetName.Emit(OpCodes.Ret); | |||
| var ilOfSetName = methodSetName.GetILGenerator(); | |||
| ilOfSetName.Emit(OpCodes.Ldarg_0); // this | |||
| ilOfSetName.Emit(OpCodes.Ldarg_1); // the first one in arguments list | |||
| ilOfSetName.Emit(OpCodes.Stfld, fieldName); | |||
| ilOfSetName.Emit(OpCodes.Ret); | |||
| // create Name property | |||
| var propertyName = typeBuilder.DefineProperty( | |||
| "Name", PropertyAttributes.None, typeof(string), null); | |||
| propertyName.SetGetMethod(methodGetName); | |||
| propertyName.SetSetMethod(methodSetName); | |||
| // ---- define methods ---- | |||
| // create ToString() method | |||
| var methodToString = typeBuilder.DefineMethod( | |||
| "ToString", | |||
| MethodAttributes.Virtual | MethodAttributes.Public, | |||
| typeof(string), | |||
| null); | |||
| var ilOfToString = methodToString.GetILGenerator(); | |||
| var local = ilOfToString.DeclareLocal(typeof(string)); // create a local variable | |||
| ilOfToString.Emit(OpCodes.Ldstr, "Id:[{0}], Name:[{1}]"); | |||
| ilOfToString.Emit(OpCodes.Ldarg_0); // this | |||
| ilOfToString.Emit(OpCodes.Ldfld, fieldId); | |||
| ilOfToString.Emit(OpCodes.Box, typeof(int)); // boxing the value type to object | |||
| ilOfToString.Emit(OpCodes.Ldarg_0); // this | |||
| ilOfToString.Emit(OpCodes.Ldfld, fieldName); | |||
| ilOfToString.Emit(OpCodes.Call, | |||
| typeof(string).GetMethod("Format", | |||
| new Type[] { typeof(string), typeof(object), typeof(object) })); | |||
| ilOfToString.Emit(OpCodes.Stloc, local); // set local variable | |||
| ilOfToString.Emit(OpCodes.Ldloc, local); // load local variable to stack | |||
| ilOfToString.Emit(OpCodes.Ret); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| using System.Reflection; | |||
| using System.Runtime.CompilerServices; | |||
| using System.Runtime.InteropServices; | |||
| // General Information about an assembly is controlled through the following | |||
| // set of attributes. Change these attribute values to modify the information | |||
| // associated with an assembly. | |||
| [assembly: AssemblyTitle("EmitCreateMembers")] | |||
| [assembly: AssemblyDescription("")] | |||
| [assembly: AssemblyConfiguration("")] | |||
| [assembly: AssemblyCompany("")] | |||
| [assembly: AssemblyProduct("EmitCreateMembers")] | |||
| [assembly: AssemblyCopyright("Copyright © 2013")] | |||
| [assembly: AssemblyTrademark("")] | |||
| [assembly: AssemblyCulture("")] | |||
| // Setting ComVisible to false makes the types in this assembly not visible | |||
| // to COM components. If you need to access a type in this assembly from | |||
| // COM, set the ComVisible attribute to true on that type. | |||
| [assembly: ComVisible(false)] | |||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | |||
| [assembly: Guid("03f6f120-a8c3-4286-98e8-ff62a5812cb0")] | |||
| // Version information for an assembly consists of the following four values: | |||
| // | |||
| // Major Version | |||
| // Minor Version | |||
| // Build Number | |||
| // Revision | |||
| // | |||
| // You can specify all the values or you can default the Build and Revision Numbers | |||
| // by using the '*' as shown below: | |||
| // [assembly: AssemblyVersion("1.0.*")] | |||
| [assembly: AssemblyVersion("1.0.0.0")] | |||
| [assembly: AssemblyFileVersion("1.0.0.0")] | |||
| @@ -0,0 +1,57 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
| <PropertyGroup> | |||
| <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||
| <Platform Condition=" '$(Platform)' == '' ">x86</Platform> | |||
| <ProductVersion>8.0.30703</ProductVersion> | |||
| <SchemaVersion>2.0</SchemaVersion> | |||
| <ProjectGuid>{38396364-FAFD-4D67-B265-32B108A797C0}</ProjectGuid> | |||
| <OutputType>Exe</OutputType> | |||
| <AppDesignerFolder>Properties</AppDesignerFolder> | |||
| <RootNamespace>EmitIntroduction</RootNamespace> | |||
| <AssemblyName>EmitIntroduction</AssemblyName> | |||
| <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> | |||
| <TargetFrameworkProfile>Client</TargetFrameworkProfile> | |||
| <FileAlignment>512</FileAlignment> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> | |||
| <PlatformTarget>x86</PlatformTarget> | |||
| <DebugSymbols>true</DebugSymbols> | |||
| <DebugType>full</DebugType> | |||
| <Optimize>false</Optimize> | |||
| <OutputPath>bin\Debug\</OutputPath> | |||
| <DefineConstants>DEBUG;TRACE</DefineConstants> | |||
| <ErrorReport>prompt</ErrorReport> | |||
| <WarningLevel>4</WarningLevel> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> | |||
| <PlatformTarget>x86</PlatformTarget> | |||
| <DebugType>pdbonly</DebugType> | |||
| <Optimize>true</Optimize> | |||
| <OutputPath>bin\Release\</OutputPath> | |||
| <DefineConstants>TRACE</DefineConstants> | |||
| <ErrorReport>prompt</ErrorReport> | |||
| <WarningLevel>4</WarningLevel> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <Reference Include="System" /> | |||
| <Reference Include="System.Core" /> | |||
| <Reference Include="System.Xml.Linq" /> | |||
| <Reference Include="System.Data.DataSetExtensions" /> | |||
| <Reference Include="Microsoft.CSharp" /> | |||
| <Reference Include="System.Data" /> | |||
| <Reference Include="System.Xml" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <Compile Include="Program.cs" /> | |||
| <Compile Include="Properties\AssemblyInfo.cs" /> | |||
| </ItemGroup> | |||
| <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
| <!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||
| Other similar extension points exist, see Microsoft.Common.targets. | |||
| <Target Name="BeforeBuild"> | |||
| </Target> | |||
| <Target Name="AfterBuild"> | |||
| </Target> | |||
| --> | |||
| </Project> | |||
| @@ -0,0 +1,54 @@ | |||
| using System; | |||
| using System.Reflection; | |||
| using System.Reflection.Emit; | |||
| namespace EmitIntroduction | |||
| { | |||
| class Program | |||
| { | |||
| static void Main(string[] args) | |||
| { | |||
| // specify a new assembly name | |||
| var assemblyName = new AssemblyName("Kitty"); | |||
| // create assembly builder | |||
| var assemblyBuilder = AppDomain.CurrentDomain | |||
| .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); | |||
| // create module builder | |||
| var moduleBuilder = assemblyBuilder.DefineDynamicModule("KittyModule", "Kitty.exe"); | |||
| // create type builder for a class | |||
| var typeBuilder = moduleBuilder.DefineType("HelloKittyClass", TypeAttributes.Public); | |||
| // create method builder | |||
| var methodBuilder = typeBuilder.DefineMethod( | |||
| "SayHelloMethod", | |||
| MethodAttributes.Public | MethodAttributes.Static, | |||
| null, | |||
| null); | |||
| // then get the method il generator | |||
| var il = methodBuilder.GetILGenerator(); | |||
| // then create the method function | |||
| il.Emit(OpCodes.Ldstr, "Hello, Kitty!"); | |||
| il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); | |||
| il.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine")); | |||
| il.Emit(OpCodes.Pop); // we just read something here, throw it. | |||
| il.Emit(OpCodes.Ret); | |||
| // then create the whole class type | |||
| var helloKittyClassType = typeBuilder.CreateType(); | |||
| // set entry point for this assembly | |||
| assemblyBuilder.SetEntryPoint(helloKittyClassType.GetMethod("SayHelloMethod")); | |||
| // save assembly | |||
| assemblyBuilder.Save("Kitty.exe"); | |||
| Console.WriteLine("Hi, Dennis, a Kitty assembly has been generated for you."); | |||
| Console.ReadLine(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| using System.Reflection; | |||
| using System.Runtime.CompilerServices; | |||
| using System.Runtime.InteropServices; | |||
| // General Information about an assembly is controlled through the following | |||
| // set of attributes. Change these attribute values to modify the information | |||
| // associated with an assembly. | |||
| [assembly: AssemblyTitle("EmitIntroduction")] | |||
| [assembly: AssemblyDescription("")] | |||
| [assembly: AssemblyConfiguration("")] | |||
| [assembly: AssemblyCompany("")] | |||
| [assembly: AssemblyProduct("EmitIntroduction")] | |||
| [assembly: AssemblyCopyright("Copyright © 2013")] | |||
| [assembly: AssemblyTrademark("")] | |||
| [assembly: AssemblyCulture("")] | |||
| // Setting ComVisible to false makes the types in this assembly not visible | |||
| // to COM components. If you need to access a type in this assembly from | |||
| // COM, set the ComVisible attribute to true on that type. | |||
| [assembly: ComVisible(false)] | |||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | |||
| [assembly: Guid("9ecfd944-391f-44be-8ba2-504d10c2c2e4")] | |||
| // Version information for an assembly consists of the following four values: | |||
| // | |||
| // Major Version | |||
| // Minor Version | |||
| // Build Number | |||
| // Revision | |||
| // | |||
| // You can specify all the values or you can default the Build and Revision Numbers | |||
| // by using the '*' as shown below: | |||
| // [assembly: AssemblyVersion("1.0.*")] | |||
| [assembly: AssemblyVersion("1.0.0.0")] | |||
| [assembly: AssemblyFileVersion("1.0.0.0")] | |||
| @@ -0,0 +1,32 @@ | |||
| | |||
| Microsoft Visual Studio Solution File, Format Version 11.00 | |||
| # Visual Studio 2010 | |||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmitIntroduction", "EmitIntroduction\EmitIntroduction.csproj", "{38396364-FAFD-4D67-B265-32B108A797C0}" | |||
| EndProject | |||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmitCreateMembers", "EmitCreateMembers\EmitCreateMembers.csproj", "{C4DFB7F2-8C56-4036-B4FF-E56B456B3943}" | |||
| EndProject | |||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmitCreateDynamicProxy", "EmitCreateDynamicProxy\EmitCreateDynamicProxy.csproj", "{BDA6268A-ADF2-4DA3-8053-81CA4AD007B0}" | |||
| EndProject | |||
| Global | |||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
| Debug|x86 = Debug|x86 | |||
| Release|x86 = Release|x86 | |||
| EndGlobalSection | |||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
| {38396364-FAFD-4D67-B265-32B108A797C0}.Debug|x86.ActiveCfg = Debug|x86 | |||
| {38396364-FAFD-4D67-B265-32B108A797C0}.Debug|x86.Build.0 = Debug|x86 | |||
| {38396364-FAFD-4D67-B265-32B108A797C0}.Release|x86.ActiveCfg = Release|x86 | |||
| {38396364-FAFD-4D67-B265-32B108A797C0}.Release|x86.Build.0 = Release|x86 | |||
| {C4DFB7F2-8C56-4036-B4FF-E56B456B3943}.Debug|x86.ActiveCfg = Debug|x86 | |||
| {C4DFB7F2-8C56-4036-B4FF-E56B456B3943}.Debug|x86.Build.0 = Debug|x86 | |||
| {C4DFB7F2-8C56-4036-B4FF-E56B456B3943}.Release|x86.ActiveCfg = Release|x86 | |||
| {C4DFB7F2-8C56-4036-B4FF-E56B456B3943}.Release|x86.Build.0 = Release|x86 | |||
| {BDA6268A-ADF2-4DA3-8053-81CA4AD007B0}.Debug|x86.ActiveCfg = Debug|x86 | |||
| {BDA6268A-ADF2-4DA3-8053-81CA4AD007B0}.Debug|x86.Build.0 = Debug|x86 | |||
| {BDA6268A-ADF2-4DA3-8053-81CA4AD007B0}.Release|x86.ActiveCfg = Release|x86 | |||
| {BDA6268A-ADF2-4DA3-8053-81CA4AD007B0}.Release|x86.Build.0 = Release|x86 | |||
| EndGlobalSection | |||
| GlobalSection(SolutionProperties) = preSolution | |||
| HideSolutionNode = FALSE | |||
| EndGlobalSection | |||
| EndGlobal | |||