李敢 преди 6 години
родител
ревизия
86c91f0737

+ 3
- 3
EmitCreateDynamicProxy/DDD.cs Целия файл

@@ -6,11 +6,11 @@ using System.Text;

namespace EmitCreateDynamicProxy
{
class DDD : INotifyPropertyChanged
class DDD// : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
//public event PropertyChangedEventHandler PropertyChanged;

public string Name { get => _Name; set { _Name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("uuu")); } }
public string Name { get => _Name; set { _Name = value; } } //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); } }
private string _Name = "";
}
}

+ 46
- 39
EmitCreateDynamicProxy/DynamicProxyGenerator.cs Целия файл

@@ -67,15 +67,25 @@ namespace EmitCreateDynamicProxy
string proxyClassName = string.Format(ProxyClassNameFormater, typeNeedProxy.Name);
//动态创建类代理
TypeBuilder typeBuilderProxy = moduleBuilder.DefineType(proxyClassName, TypeAttributes.Public, typeNeedProxy);
//定义一个变量存放属性变更名
FieldBuilder fbModifiedPropertyNames = typeBuilderProxy.DefineField(ModifiedPropertyNamesFieldName, modifiedPropertyNamesType, FieldAttributes.Public);

/*
* 构造函数 实例化 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.Call, typeNeedProxy.GetConstructor(Type.EmptyTypes));
ilgCtor.Emit(OpCodes.Nop);
ilgCtor.Emit(OpCodes.Ret);//返回

//定义接口
var pt = typeof(PropertyChangedEventHandler);
typeBuilderProxy.AddInterfaceImplementation(typeof(INotifyPropertyChanged));
var eil = typeBuilderProxy.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler));
var eil = typeBuilderProxy.DefineEvent("PropertyChanged", EventAttributes.SpecialName, typeof(PropertyChangedEventHandler));

//add field
var eb = typeBuilderProxy.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private);
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
@@ -86,7 +96,7 @@ namespace EmitCreateDynamicProxy
| 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");
mb.DefineParameter(1, ParameterAttributes.None, "value");
var il = mb.GetILGenerator();
il.DeclareLocal(pt);
il.DeclareLocal(pt);
@@ -114,10 +124,12 @@ namespace EmitCreateDynamicProxy
il.Emit(OpCodes.Bne_Un_S, lable);
il.Emit(OpCodes.Ret);

eil.SetAddOnMethod(mb);

//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");
mb.DefineParameter(1, ParameterAttributes.None, "value");

il = mb.GetILGenerator();
il.DeclareLocal(pt);
@@ -146,16 +158,7 @@ namespace EmitCreateDynamicProxy
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);//返回
eil.SetRemoveOnMethod(mb);

//获取被代理对象的所有属性,循环属性进行重写
PropertyInfo[] properties = typeNeedProxy.GetProperties();
@@ -164,26 +167,35 @@ namespace EmitCreateDynamicProxy
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);

PropertyBuilder propertyBuilder = typeBuilderProxy.DefineProperty(propertyName, PropertyAttributes.None, typePepropertyInfo, Type.EmptyTypes);
//重写属性的Get Set方法
//Method 搞的一直调用不成功,应该是写的时候没有加上CheckAccessOnOverride
var methodGet = typeBuilderProxy.DefineMethod("get_" + propertyName, GetSetMethodAttributes, typePepropertyInfo, Type.EmptyTypes);
var methodSet = typeBuilderProxy.DefineMethod("set_" + propertyName, GetSetMethodAttributes, null, new Type[] { typePepropertyInfo });
var methodSet = typeBuilderProxy.DefineMethod("set_" + propertyName, GetSetMethodAttributes, typeof(void), new Type[] { typePepropertyInfo });

//il of get method
var ilGetMethod = methodGet.GetILGenerator();
ilGetMethod.Emit(OpCodes.Nop);
ilGetMethod.Emit(OpCodes.Ldstr, "Before Do");
ilGetMethod.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
ilGetMethod.Emit(OpCodes.Ldarg_0);
ilGetMethod.Emit(OpCodes.Ldfld, fieldBuilder);
ilGetMethod.Emit(OpCodes.Call, typeNeedProxy.GetMethod("get_" + propertyName));
ilGetMethod.Emit(OpCodes.Ret);
//il of set method
methodSet.DefineParameter(0, ParameterAttributes.Retval, null);
methodSet.DefineParameter(1, ParameterAttributes.None, "value");
ILGenerator ilSetMethod = methodSet.GetILGenerator();
var nullLabel = ilSetMethod.DefineLabel();
ilSetMethod.Emit(OpCodes.Nop);
ilSetMethod.Emit(OpCodes.Ldarg_0);
ilSetMethod.Emit(OpCodes.Ldarg_1);
ilSetMethod.Emit(OpCodes.Stfld, fieldBuilder);
ilSetMethod.Emit(OpCodes.Call, typeNeedProxy.GetMethod("set_" + propertyName));
ilSetMethod.Emit(OpCodes.Nop);
ilSetMethod.Emit(OpCodes.Ldstr, "Before Do");
ilSetMethod.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
ilSetMethod.Emit(OpCodes.Nop);
ilSetMethod.Emit(OpCodes.Ldarg_0);
ilSetMethod.Emit(OpCodes.Ldfld, fbModifiedPropertyNames);
ilSetMethod.Emit(OpCodes.Ldfld, eb);
ilSetMethod.Emit(OpCodes.Dup);
ilSetMethod.Emit(OpCodes.Brtrue_S, nullLabel);
ilSetMethod.Emit(OpCodes.Pop);
@@ -192,12 +204,21 @@ namespace EmitCreateDynamicProxy
ilSetMethod.MarkLabel(nullLabel);
ilSetMethod.Emit(OpCodes.Ldarg_0);
ilSetMethod.Emit(OpCodes.Ldstr, propertyInfo.Name);
ilSetMethod.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs));
ilSetMethod.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs).GetConstructor(new Type[] { typeof(string) }));
ilSetMethod.Emit(OpCodes.Callvirt, pt.GetMethod("Invoke", new Type[] { typeof(object), typeof(PropertyChangedEventArgs) }));
ilSetMethod.Emit(OpCodes.Nop);
il.MarkLabel(retLabel);
ilSetMethod.Emit(OpCodes.Ldstr, "After Do");
ilSetMethod.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
ilSetMethod.Emit(OpCodes.Nop);
ilSetMethod.MarkLabel(retLabel);
ilSetMethod.Emit(OpCodes.Ret);

//ilSetMethod.Emit(OpCodes.Nop);
//ilSetMethod.Emit(OpCodes.Ldarg_0);
//ilSetMethod.Emit(OpCodes.Ldarg_1);
//ilSetMethod.Emit(OpCodes.Stfld, fieldBuilder);
//ilSetMethod.Emit(OpCodes.Ret);

//设置属性的Get Set方法
propertyBuilder.SetGetMethod(methodGet);
propertyBuilder.SetSetMethod(methodSet);
@@ -213,20 +234,6 @@ namespace EmitCreateDynamicProxy
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()

+ 1
- 0
EmitCreateDynamicProxy/EmitCreateDynamicProxy.csproj Целия файл

@@ -45,6 +45,7 @@
<ItemGroup>
<Compile Include="DDD.cs" />
<Compile Include="DynamicProxyGenerator.cs" />
<Compile Include="M.cs" />
<Compile Include="Model.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

+ 24
- 0
EmitCreateDynamicProxy/M.cs Целия файл

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace EmitCreateDynamicProxy
{
class M : Model, INotifyPropertyChanged
{
public override string Name
{
get => base.Name; set
{
base.Name = value;
Console.WriteLine("Before");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
Console.WriteLine("After");
}
}

public event PropertyChangedEventHandler PropertyChanged;
}
}

+ 1
- 3
EmitCreateDynamicProxy/Model.cs Целия файл

@@ -7,8 +7,6 @@ namespace EmitCreateDynamicProxy
{
public class Model
{
public virtual string LoginName { get; set; }

public virtual string Password { get; set; }
public virtual string Name { get; set; }
}
}

+ 16
- 2
EmitCreateDynamicProxy/Program.cs Целия файл

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
@@ -17,8 +18,21 @@ namespace EmitCreateDynamicProxy
//Console.ReadLine();

Model m = DynamicProxyGenerator.CreateDynamicProxy<Model>(true);
m.LoginName = "ddd";
HashSet<string> modifiedPropertyNames = DynamicProxyGenerator.GetModifiedProperties(m) as HashSet<string>;
var pc = m as INotifyPropertyChanged;
pc.PropertyChanged += Pc_PropertyChanged;
m.Name = "ddd";
var d = new DDD();
//d.PropertyChanged += Pc_PropertyChanged;
d.Name = "nnn";
//var x = new M();
//x.Name = "000";
Console.WriteLine("........");
Console.ReadKey();
}

private static void Pc_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine($"PropertyChanged {e.PropertyName}");
}
}


+ 25
- 2
LearningEmit.sln Целия файл

@@ -1,32 +1,55 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.329
MinimumVisualStudioVersion = 10.0.40219.1
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
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{38396364-FAFD-4D67-B265-32B108A797C0}.Debug|Any CPU.ActiveCfg = Debug|x86
{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|Any CPU.ActiveCfg = Release|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|Any CPU.ActiveCfg = Debug|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|Any CPU.ActiveCfg = Release|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|Any CPU.ActiveCfg = Debug|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|Any CPU.ActiveCfg = Release|x86
{BDA6268A-ADF2-4DA3-8053-81CA4AD007B0}.Release|x86.ActiveCfg = Release|x86
{BDA6268A-ADF2-4DA3-8053-81CA4AD007B0}.Release|x86.Build.0 = Release|x86
{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}.Debug|x86.ActiveCfg = Debug|Any CPU
{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}.Debug|x86.Build.0 = Debug|Any CPU
{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}.Release|Any CPU.Build.0 = Release|Any CPU
{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}.Release|x86.ActiveCfg = Release|Any CPU
{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B43E4E3D-CF60-498A-9F7D-51F46275BBD6}
EndGlobalSection
EndGlobal

+ 6
- 0
Test/App.config Целия файл

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
</configuration>

+ 24
- 0
Test/Program.cs Целия файл

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
class Program
{
static void Main(string[] args)
{
ModelProxy m = new ModelProxy();
m.PropertyChanged += M_PropertyChanged;
m.Name = "333";
Console.ReadLine();
}

private static void M_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
Console.WriteLine("Run Run Run");
}
}
}

+ 36
- 0
Test/Properties/AssemblyInfo.cs Целия файл

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Test")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]

// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("06cb2095-2d8d-4b3d-96d9-451bcfb095f4")]

// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

+ 59
- 0
Test/Test.csproj Целия файл

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{06CB2095-2D8D-4B3D-96D9-451BCFB095F4}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Test</RootNamespace>
<AssemblyName>Test</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</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|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="DynamicAssembly">
<HintPath>..\EmitCreateDynamicProxy\bin\Debug\DynamicAssembly.dll</HintPath>
</Reference>
<Reference Include="EmitCreateDynamicProxy">
<HintPath>..\EmitCreateDynamicProxy\bin\Debug\EmitCreateDynamicProxy.exe</HintPath>
</Reference>
<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.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Loading…
Отказ
Запис