// this runs only once the factory is ready // NOT when building models public IList CreateModelList(string alias) { var infos = EnsureModels(); // fail fast if (infos == null) { return(new List <IPublishedElement>()); } if (!infos.ModelInfos.TryGetValue(alias, out var modelInfo)) { return(new List <IPublishedElement>()); } var ctor = modelInfo.ListCtor; if (ctor != null) { return(ctor()); } var listType = typeof(List <>).MakeGenericType(modelInfo.ModelType); ctor = modelInfo.ListCtor = ReflectionUtilities.EmitConstructor <Func <IList> >(declaring: listType); return(ctor()); }
public void EmitCtorEmitsFromInfo() { var ctorInfo = typeof(Class1).GetConstructor( BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, Array.Empty <Type>(), null); var ctor1 = ReflectionUtilities.EmitConstructor <Func <Class1> >(ctorInfo); Assert.IsInstanceOf <Class1>(ctor1()); ctorInfo = typeof(Class1).GetConstructor( BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, new[] { typeof(int), }, null); var ctor3 = ReflectionUtilities.EmitConstructor <Func <int, object> >(ctorInfo); Assert.IsInstanceOf <Class1>(ctor3(42)); Assert.Throws <ArgumentException>(() => ReflectionUtilities.EmitConstructor <Func <string, object> >(ctorInfo)); }
// this runs only once the factory is ready // NOT when building models public IList CreateModelList(string?alias) { Infos infos = EnsureModels(); // fail fast if (alias is null || infos.ModelInfos is null || !infos.ModelInfos.TryGetValue(alias, out ModelInfo? modelInfo)) { return(new List <IPublishedElement>()); } Func <IList>?ctor = modelInfo.ListCtor; if (ctor != null) { return(ctor()); } if (modelInfo.ModelType is null) { return(new List <IPublishedElement>()); } Type listType = typeof(List <>).MakeGenericType(modelInfo.ModelType); ctor = modelInfo.ListCtor = ReflectionUtilities.EmitConstructor <Func <IList> >(declaring: listType); return(ctor is null ? new List <IPublishedElement>() : ctor()); }
/// <inheritdoc /> public IList?CreateModelList(string?alias) { // fail fast if (_modelInfos is null || alias is null || !_modelInfos.TryGetValue(alias, out var modelInfo) || modelInfo.ModelType is null) { return(new List <IPublishedElement>()); } var ctor = modelInfo.ListCtor; if (ctor != null) { return(ctor()); } var listType = typeof(List <>).MakeGenericType(modelInfo.ModelType); ctor = modelInfo.ListCtor = ReflectionUtilities.EmitConstructor <Func <IList> >(declaring: listType); if (ctor is not null) { return(ctor()); } return(null); }
public void EmitCtorThrowsIfInvalid() { var ctorInfo = typeof(Class1).GetConstructor( BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, Array.Empty <Type>(), null); Assert.Throws <ArgumentException>(() => ReflectionUtilities.EmitConstructor <Func <Class2> >(ctorInfo)); }
/// <summary> /// Defines an HTML string interface. /// </summary> /// <typeparam name="THtmlString">The type of the HTML string.</typeparam> /// <param name="mapping">The mapping.</param> /// <returns> /// This builder. /// </returns> /// <exception cref="System.ArgumentException"> /// THtmlString should be an interface. /// or /// THtmlString may only define one method: \"string ToHtmlString()\". /// or /// THtmlString may only define one property: \"string Html { get; }\". /// </exception> public static ModelMappingCollectionBuilder DefineHtmlString <THtmlString>(this ModelMappingCollectionBuilder mapping) where THtmlString : class { var htmlStringInterface = typeof(THtmlString); if (DefinedTypes.Contains(htmlStringInterface)) { return(mapping); } if (!htmlStringInterface.IsInterface) { throw new ArgumentException("THtmlString should be an interface."); } var stringType = typeof(string); if (htmlStringInterface.GetAllMethods().Where(m => !m.IsSpecialName).Any(m => m.Name != nameof(BaseHtmlString.ToHtmlString) || m.ReturnType != stringType || m.GetParameters().Any())) { throw new ArgumentException("THtmlString may only define one method: \"string ToHtmlString()\"."); } var properties = htmlStringInterface.GetAllProperties(); if (properties.Any(p => p.Name != nameof(BaseHtmlString.Html) || p.PropertyType != stringType || p.SetMethod != null)) { throw new ArgumentException("THtmlString may only define one property: \"string Html { get; }\"."); } var name = new AssemblyName($"ModelsMapper_{htmlStringInterface.FullName}"); var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); var module = assembly.DefineDynamicModule(name.FullName); var baseClass = typeof(BaseHtmlString); var type = module.DefineType(name.FullName, TypeAttributes.Public, baseClass, new[] { htmlStringInterface }); var constructor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { stringType }); var il = constructor.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, baseClass.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, binder: null, types: new[] { stringType }, modifiers: null)); il.Emit(OpCodes.Ret); var generatedType = type.CreateType(); TypeDescriptor.AddAttributes(htmlStringInterface, new TypeConverterAttribute(typeof(HtmlStringConverter))); var converter = (HtmlStringConverter)TypeDescriptor.GetConverter(htmlStringInterface); converter.Constructor = ReflectionUtilities.EmitConstructor <Func <string, BaseHtmlString> >(generatedType.GetConstructor(new[] { stringType })); DefinedTypes.Add(htmlStringInterface); return(mapping); }
public void EmitCtorEmits() { var ctor1 = ReflectionUtilities.EmitConstructor <Func <Class1> >(); Assert.IsInstanceOf <Class1>(ctor1()); var ctor2 = ReflectionUtilities.EmitConstructor <Func <object> >(declaring: typeof(Class1)); Assert.IsInstanceOf <Class1>(ctor2()); var ctor3 = ReflectionUtilities.EmitConstructor <Func <int, Class3> >(); Assert.IsInstanceOf <Class3>(ctor3(42)); var ctor4 = ReflectionUtilities.EmitConstructor <Func <int, object> >(declaring: typeof(Class3)); Assert.IsInstanceOf <Class3>(ctor4(42)); }
/// <summary> /// Builds the specified content type. /// </summary> /// <param name="contentType">Type of the content.</param> /// <param name="forAllModelMaps">For all model maps.</param> public void Build(IContentTypeComposition?contentType, IDictionary <Type, ModelMap> forAllModelMaps) { if (contentType == null) { return; } if (this.GeneratedType != null) { this.FixMissingImplementations(contentType); return; } this.forAllModelMaps = forAllModelMaps; var name = new AssemblyName($"ModelsMapper_{this.Type.FullName}"); var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); var module = assembly.DefineDynamicModule(name.FullName); var type = this.BuildType(module, contentType); this.BuildProperties(type, this.Type.GetAllProperties(), contentType); this.BuildMethods(type, this.Type.GetAllMethods()); this.BuildConstructor(type); var proxy = this.GeneratedType = type.CreateType(); foreach (var implementation in this.Implementations) { proxy.GetField(GetImplementationFieldName(implementation.Key), BindingFlags.Static | BindingFlags.NonPublic) ?.SetValue(null, implementation.Value); } foreach (var converter in this.converters.ToList()) { FieldInfo field = proxy.GetField(GetConverterFieldName(converter.Key), BindingFlags.Static | BindingFlags.NonPublic); this.converters[converter.Key] = field; field.SetValue( obj: null, value: TypeDescriptor.GetProperties(converter.Key.DeclaringType).Find(converter.Key.Name, ignoreCase: false).Converter); } this.Ctor = ReflectionUtilities.EmitConstructor <Func <IPublishedElement, IPublishedElement> >(declaring: proxy); }
public void Setup() { var ctorArgTypes = new[] { typeof(IFoo) }; var type = typeof(Foo); var constructor = _ctorInfo = type.GetConstructor(ctorArgTypes); if (constructor == null) { throw new Exception("Failed to get the ctor."); } //IL_0000: ldarg.0 // this //IL_0001: ldfld class Umbraco.Tests.Benchmarks.CtorInvokeBenchmarks/IFoo Umbraco.Tests.Benchmarks.CtorInvokeBenchmarks::_foo //IL_0006: newobj instance void Umbraco.Tests.Benchmarks.CtorInvokeBenchmarks/Foo::.ctor(class Umbraco.Tests.Benchmarks.CtorInvokeBenchmarks/IFoo) //IL_000b: pop //IL_000c: ret // generate a dynamic method // // ldarg.0 // obj0 // newobj instance void [Umbraco.Tests.Benchmarks]Umbraco.Tests.Benchmarks.CtorInvokeBenchmarks / Foo::.ctor(class [Umbraco.Tests.Benchmarks] Umbraco.Tests.Benchmarks.CtorInvokeBenchmarks/IFoo) // ret var meth = new DynamicMethod(string.Empty, typeof(IFoo), ctorArgTypes, type.Module, true); var gen = meth.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Newobj, constructor); gen.Emit(OpCodes.Ret); _dynamicMethod = (Func <IFoo, IFoo>)meth.CreateDelegate(typeof(Func <IFoo, IFoo>)); // generate a compiled expression // // ldarg.0 // content // newobj instance void [Umbraco.Tests.Benchmarks]Umbraco.Tests.Benchmarks.CtorInvokeBenchmarks / Foo::.ctor(class [Umbraco.Tests.Benchmarks] Umbraco.Tests.Benchmarks.CtorInvokeBenchmarks/IFoo) // ret var exprArg = Expression.Parameter(typeof(IFoo), "content"); var exprNew = Expression.New(constructor, exprArg); var expr = Expression.Lambda <Func <IFoo, IFoo> >(exprNew, exprArg); _expressionMethod = expr.Compile(); // create a dynamic assembly // dump to disk so we can review IL code with eg DotPeek var assemblyName = new AssemblyName("Umbraco.Tests.Benchmarks.IL"); var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save); var module = assembly.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll"); var typeBuilder = module.DefineType("CtorInvoke", TypeAttributes.Public | TypeAttributes.Abstract); var expressionMethodBuilder = typeBuilder.DefineMethod("ExpressionCtor", MethodAttributes.Public | MethodAttributes.Static, // CompileToMethod requires a static method typeof(IFoo), ctorArgTypes); expr.CompileToMethod(expressionMethodBuilder); var dynamicMethodBuilder = typeBuilder.DefineMethod("DynamicCtor", MethodAttributes.Public | MethodAttributes.Static, typeof(IFoo), ctorArgTypes); gen = dynamicMethodBuilder.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Newobj, constructor); gen.Emit(OpCodes.Ret); meth.CreateDelegate(typeof(Func <IFoo, IFoo>)); var btype = typeBuilder.CreateType(); // need to build before saving assembly.Save("Umbraco.Tests.Benchmarks.IL.dll"); // at that point, // _dynamicMethod is 2x slower than direct ctor // _expressionMethod is 6x slower than direct ctor // which is weird as inspecting the assembly IL shows that they are generated // exactly the same, and yet it is confirmed eg by https://stackoverflow.com/questions/4211418 // // not sure why exactly // see https://stackoverflow.com/questions/13431573 // see http://mattwarren.org/2017/01/25/How-do-.NET-delegates-work/#different-types-of-delegates // // note that all the benchmark methods have the very same IL code so it's // really the 'callvirt ...' that ends up doing different things // // more readings: // http://byterot.blogspot.dk/2012/05/performance-comparison-of-code.html // https://stackoverflow.com/questions/1296683 // https://stackoverflow.com/questions/44239127 // that last one points to // https://blogs.msdn.microsoft.com/seteplia/2017/02/01/dissecting-the-new-constraint-in-c-a-perfect-example-of-a-leaky-abstraction/ // which reads ... "Expression.Compile creates a DynamicMethod and associates it with an anonymous assembly // to run it in a sandboxed environment. This makes it safe for a dynamic method to be emitted and executed // by partially trusted code but adds some run-time overhead." // and, turning things into a delegate (below) removes that overhead... // turning it into a delegate seems cool, _expressionMethod2 is ~ _dynamicMethod _expressionMethod2 = (Func <IFoo, IFoo>)Delegate.CreateDelegate(typeof(Func <IFoo, IFoo>), btype.GetMethod("ExpressionCtor")); // nope, this won't work, throws an ArgumentException because 'MethodInfo must be a MethodInfo object' // and here it's of type System.Reflection.Emit.DynamicMethod+RTDynamicMethod - whereas the btype one is ok // so, the dynamic assembly step is required // //_expressionMethod3 = (Func<IFoo, IFoo>) Delegate.CreateDelegate(typeof (Func<IFoo, IFoo>), _expressionMethod.Method); // but, our utilities know how to do it! _expressionMethod3 = ReflectionUtilities.CompileToDelegate(expr); _expressionMethod4 = ReflectionUtilities.GetCtor <Foo, IFoo>(); // however, unfortunately, the generated "compiled to delegate" code cannot access private stuff :( _emittedCtor = ReflectionUtilities.EmitConstructor <Func <IFoo, Foo> >(); }
public void EmitCtor() { var ctor = ReflectionUtilities.EmitConstructor <Func <IFoo, Foo> >(); var foo = ctor(_foo); }
public void EmitCtorReturnsNull() { Assert.IsNull(ReflectionUtilities.EmitConstructor <Func <bool, Class3> >(false)); }
public void EmitCtorThrowsIfNotFound() { Assert.Throws <InvalidOperationException>(() => ReflectionUtilities.EmitConstructor <Func <bool, Class3> >()); }
public void EmitCtorEmitsPrivateCtor() { var ctor = ReflectionUtilities.EmitConstructor <Func <string, Class3> >(); Assert.IsInstanceOf <Class3>(ctor("foo")); }