⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bytecodeproviderimpl.cs

📁 NHibernate NET开发者所需的
💻 CS
字号:
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text;
using log4net;
using Microsoft.CSharp;
using NHibernate.Properties;

namespace NHibernate.Bytecode.CodeDom
{
	/// <summary>
	/// CodeDOM-based bytecode provider.
	/// </summary>
	public class BytecodeProviderImpl : IBytecodeProvider
	{
		private static readonly ILog log = LogManager.GetLogger(typeof(BytecodeProviderImpl));

		#region IBytecodeProvider Members

		public IProxyFactoryFactory ProxyFactoryFactory
		{
			get { return new DefaultProxyFactoryFactory(); }
		}


		public IReflectionOptimizer GetReflectionOptimizer(System.Type clazz, IGetter[] getters, ISetter[] setters)
		{
			if (clazz.IsValueType)
			{
				// Cannot create optimizer for value types - the setter method will not work.
				log.Info("Disabling reflection optimizer for value type " + clazz.FullName);
				return null;
			}
			return new Generator(clazz, getters, setters).CreateReflectionOptimizer();
		}

		#endregion

		public class Generator
		{
			private CompilerParameters cp = new CompilerParameters();
			private System.Type mappedClass;
			private IGetter[] getters;
			private ISetter[] setters;

			/// <summary>
			/// ctor
			/// </summary>
			/// <param name="mappedClass">The target class</param>
			/// <param name="setters">Array of setters</param>
			/// <param name="getters">Array of getters</param>
			public Generator(System.Type mappedClass, IGetter[] getters, ISetter[] setters)
			{
				this.mappedClass = mappedClass;
				this.getters = getters;
				this.setters = setters;
			}

			public IReflectionOptimizer CreateReflectionOptimizer()
			{
				try
				{
					InitCompiler();
					return Build(GenerateCode());
				}
				catch (Exception e)
				{
					log.Info("Disabling reflection optimizer for class " + mappedClass.FullName);
					log.Debug("CodeDOM compilation failed", e);
					return null;
				}
			}

			/// <summary>
			/// Set up the compiler options
			/// </summary>
			private void InitCompiler()
			{
				if (log.IsDebugEnabled)
				{
					log.Debug("Init compiler for class " + mappedClass.FullName);
				}

				cp.GenerateInMemory = true;
				cp.TreatWarningsAsErrors = true;
#if ! DEBUG
				cp.CompilerOptions = "/optimize";
#endif

				AddAssembly(Assembly.GetExecutingAssembly().Location);

				Assembly classAssembly = mappedClass.Assembly;
				AddAssembly(classAssembly.Location);

				foreach (AssemblyName referencedName in classAssembly.GetReferencedAssemblies())
				{
					Assembly referencedAssembly = Assembly.Load(referencedName);
					AddAssembly(referencedAssembly.Location);
				}
			}

			/// <summary>
			/// Add an assembly to the list of ReferencedAssemblies
			/// required to build the class
			/// </summary>
			/// <param name="name"></param>
			private void AddAssembly(string name)
			{
				if (name.StartsWith("System.")) return;

				if (!cp.ReferencedAssemblies.Contains(name))
				{
					if (log.IsDebugEnabled)
					{
						log.Debug("Adding referenced assembly " + name);
					}
					cp.ReferencedAssemblies.Add(name);
				}
			}

			/// <summary>
			/// Build the generated code
			/// </summary>
			/// <param name="code">Generated code</param>
			/// <returns>An instance of the generated class</returns>
			private IReflectionOptimizer Build(string code)
			{
				CodeDomProvider provider = new CSharpCodeProvider();
				CompilerResults res = provider.CompileAssemblyFromSource(cp, new string[] {code});

				if (res.Errors.HasErrors)
				{
					log.Debug("Compiled with error:\n" + code);
					foreach (CompilerError e in res.Errors)
					{
						log.Debug(
							String.Format("Line:{0}, Column:{1} Message:{2}",
							              e.Line, e.Column, e.ErrorText)
							);
					}
					throw new InvalidOperationException(res.Errors[0].ErrorText);
				}
				else
				{
					if (log.IsDebugEnabled)
					{
						log.Debug("Compiled ok:\n" + code);
					}
				}

				Assembly assembly = res.CompiledAssembly;
				System.Type[] types = assembly.GetTypes();
				IReflectionOptimizer optimizer = (IReflectionOptimizer) assembly.CreateInstance(types[0].FullName, false,
				                                                                                BindingFlags.CreateInstance, null,
				                                                                                new object[] {setters, getters},
				                                                                                null, null);

				return optimizer;
			}

			private const string header =
				"using System;\n" +
				"using NHibernate.Property;\n" +
				"namespace NHibernate.Bytecode.CodeDom {\n";

			private const string classDef =
				@"public class GetSetHelper_{0} : IReflectionOptimizer, IAccessOptimizer {{
					ISetter[] setters;
					IGetter[] getters;
					
					public GetSetHelper_{0}(ISetter[] setters, IGetter[] getters) {{
						this.setters = setters;
						this.getters = getters;
					}}

					public IInstantiationOptimizer InstantiationOptimizer {{
						get {{ return null; }}
					}}

					public IAccessOptimizer AccessOptimizer {{
						get {{ return this; }}
					}}
					";

			private const string startSetMethod =
				"public void SetPropertyValues(object obj, object[] values) {{\n" +
				"  {0} t = ({0})obj;\n";

			private const string closeSetMethod =
				"}\n";

			private const string startGetMethod =
				"public object[] GetPropertyValues(object obj) {{\n" +
				"  {0} t = ({0})obj;\n" +
				"  object[] ret = new object[{1}];\n";

			private const string closeGetMethod =
				"  return ret;\n" +
				"}\n";

			/// <summary>
			/// Check if the property is public
			/// </summary>
			/// <remarks>
			/// <para>If IsPublic==true I can directly set the property</para>
			/// <para>If IsPublic==false I need to use the setter/getter</para>
			/// </remarks>
			/// <param name="propertyName"></param>
			/// <returns></returns>
			private bool IsPublic(string propertyName)
			{
				return mappedClass.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public) != null;
			}

			/// <summary>
			/// Generate the required code
			/// </summary>
			/// <returns>C# code</returns>
			private string GenerateCode()
			{
				StringBuilder sb = new StringBuilder();

				sb.Append(header);
				sb.AppendFormat(classDef, mappedClass.FullName.Replace('.', '_').Replace("+", "__"));

				sb.AppendFormat(startSetMethod, mappedClass.FullName.Replace('+', '.'));
				for (int i = 0; i < setters.Length; i++)
				{
					ISetter setter = setters[i];

					if (setter is BasicPropertyAccessor.BasicSetter && IsPublic(setter.PropertyName))
					{
						System.Type type = getters[i].ReturnType;

						if (type.IsValueType)
						{
							sb.AppendFormat(
								"  t.{0} = values[{2}] == null ? new {1}() : ({1})values[{2}];\n",
								setter.PropertyName,
								type.FullName.Replace('+', '.'),
								i);
						}
						else
						{
							sb.AppendFormat("  t.{0} = ({1})values[{2}];\n",
							                setter.PropertyName,
							                type.FullName.Replace('+', '.'),
							                i);
						}
					}
					else
					{
						sb.AppendFormat("  setters[{0}].Set(obj, values[{0}]);\n", i);
					}
				}
				sb.Append(closeSetMethod); // Close Set

				sb.AppendFormat(startGetMethod, mappedClass.FullName.Replace('+', '.'), getters.Length);
				for (int i = 0; i < getters.Length; i++)
				{
					IGetter getter = getters[i];
					if (getter is BasicPropertyAccessor.BasicGetter && IsPublic(getter.PropertyName))
					{
						sb.AppendFormat("  ret[{0}] = t.{1};\n", i, getter.PropertyName);
					}
					else
					{
						sb.AppendFormat("  ret[{0}] = getters[{0}].Get(obj);\n", i);
					}
				}
				sb.Append(closeGetMethod);

				sb.Append("}\n"); // Close class
				sb.Append("}\n"); // Close namespace

				return sb.ToString();
			}
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -