Esempio n. 1
0
        // 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));
    }
Esempio n. 6
0
        /// <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);
        }
Esempio n. 7
0
        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);
 }
Esempio n. 11
0
 public void EmitCtorReturnsNull()
 {
     Assert.IsNull(ReflectionUtilities.EmitConstructor <Func <bool, Class3> >(false));
 }
Esempio n. 12
0
 public void EmitCtorThrowsIfNotFound()
 {
     Assert.Throws <InvalidOperationException>(() => ReflectionUtilities.EmitConstructor <Func <bool, Class3> >());
 }
Esempio n. 13
0
        public void EmitCtorEmitsPrivateCtor()
        {
            var ctor = ReflectionUtilities.EmitConstructor <Func <string, Class3> >();

            Assert.IsInstanceOf <Class3>(ctor("foo"));
        }