Example #1
0
        public string Generate(CodeGenerationContext context, Type baseType, MethodInfo[] interceptableMethods)
        {
            context.References.Add(baseType.Assembly);
            var proxyClassName = GetInterceptableProxyClassName(baseType, out var constraints);

            context.WriteLines($"public sealed class {proxyClassName} : {baseType.GetOutputName()}, IVirtualMethodProxy");

            #region  Generic argument constraints.
            if (constraints is not null)
            {
                using (context.Indent())
                {
                    foreach (var constraint in constraints)
                    {
                        context.WriteLines(constraint);
                    }
                }
            }
            #endregion

            using (context.CodeBlock())
            {
                #region Fields
                GenerateFields(context, baseType, null, interceptableMethods, out var methodInfoAccessorFieldNames, out var invokerAccessorFieldNames, out var invokerMethodNames);
                context.WriteLines();
                #endregion

                #region InvocationContextClasses.
                var invocationContextClassNames = new Dictionary <MethodInfo, string>();
                foreach (var method in interceptableMethods)
                {
                    var className = ResolveInvocationContextClassName(method);
                    invocationContextClassNames[method] = GenerateInvocationContextClass(context, className, method);
                    context.WriteLines();
                }
                #endregion

                #region Properties
                var properties = baseType.GetProperties();
                if (properties.Any())
                {
                    foreach (var property in properties)
                    {
                        string?getInvocationContextClassName = null;
                        string?setInvocationContextClassName = null;
                        string?getInvokerFieldName           = null;
                        string?setInvokerFieldName           = null;
                        string?getMethodAccessor             = null;
                        string?setMethodAccessor             = null;
                        var    getMethod = property.GetMethod;
                        var    setMethod = property.SetMethod;
                        if (getMethod != null)
                        {
                            if (methodInfoAccessorFieldNames.TryGetValue(getMethod, out var accessor))
                            {
                                getMethodAccessor = $"{accessor}.Value";
                            }
                        }
                        if (setMethod != null)
                        {
                            if (methodInfoAccessorFieldNames.TryGetValue(setMethod, out var accessor))
                            {
                                setMethodAccessor = $"{accessor}.Value";
                            }
                        }
                        if (getMethod != null)
                        {
                            invocationContextClassNames.TryGetValue(getMethod, out getInvocationContextClassName);
                            invokerAccessorFieldNames?.TryGetValue(getMethod, out getInvokerFieldName);
                        }
                        if (setMethod != null)
                        {
                            invocationContextClassNames.TryGetValue(setMethod, out setInvocationContextClassName);
                            invokerAccessorFieldNames?.TryGetValue(setMethod, out setInvokerFieldName);
                        }

                        if (!string.IsNullOrWhiteSpace(getInvocationContextClassName) || !string.IsNullOrWhiteSpace(setInvocationContextClassName))
                        {
                            GenerateProperty(context, property, getInvocationContextClassName, setInvocationContextClassName, getMethodAccessor, setMethodAccessor, getInvokerFieldName, setInvokerFieldName, null);
                        }
                    }
                }
                #endregion

                #region Constructors
                var constructorName = proxyClassName;
                if (baseType.IsGenericTypeDefinition)
                {
                    var index = constructorName.IndexOf('<');
                    constructorName = proxyClassName[..index];
Example #2
0
        public override bool TryGenerate(ServiceDescriptor serviceDescriptor, CodeGenerationContext codeGenerationContext, out string[]?proxyTypeNames)
        {
            proxyTypeNames = null;
            var @interface = serviceDescriptor.ServiceType;

            if ([email protected])
            {
                return(false);
            }
            var implementationType = serviceDescriptor.ImplementationType;

            if (implementationType == null)
            {
                return(false);
            }

            Validate(implementationType);

            if ([email protected] && [email protected])
            {
                return(false);
            }

            var methods = implementationType
                          .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(it => it.IsPublic || it.IsFamily || it.IsFamilyAndAssembly)
                          .Where(it => it.DeclaringType != typeof(object))
            ;
            var interceptableMethods = methods.Where(it => _methodInvokerBuilder.CanIntercept(implementationType, it));

            if (!interceptableMethods.Any())
            {
                return(false);
            }

            foreach (var method in methods)
            {
                codeGenerationContext.References.Add(method.ReturnType.Assembly);
                foreach (var parameter in method.GetParameters())
                {
                    codeGenerationContext.References.Add(parameter.ParameterType.Assembly);
                }
            }

            MethodInfo[] interfaceMethods;
            MethodInfo[] targetMethods;
            if (@interface.IsGenericTypeDefinition && implementationType.IsGenericTypeDefinition)
            {
                GetGenericInterfaceMapping(@interface, implementationType, out interfaceMethods, out targetMethods);
            }
            else
            {
                var map = implementationType.GetInterfaceMap(@interface);
                interfaceMethods = map.InterfaceMethods;
                targetMethods    = map.TargetMethods;
            }


            var    nonInterfaceMethods    = interceptableMethods.Except(targetMethods).Where(it => it.IsVirtual);
            string?virtualMethodClassName = null;

            if (nonInterfaceMethods.Any())
            {
                virtualMethodClassName = _virtualMethodProxyGeneratorAccessor.Value.Generate(codeGenerationContext, implementationType, nonInterfaceMethods.ToArray());
            }

            if (!interceptableMethods.Intersect(targetMethods).Any())
            {
                proxyTypeNames = new string[] { virtualMethodClassName ! };
                return(true);
            }

            var interfaceProxyName = GenerateCore(codeGenerationContext, @interface, implementationType, interfaceMethods, targetMethods, virtualMethodClassName ?? implementationType.GetOutputName());

            proxyTypeNames = string.IsNullOrEmpty(virtualMethodClassName) ? new string[] { interfaceProxyName } : new string[] { interfaceProxyName, virtualMethodClassName };
            return(true);
        }