Exemple #1
0
        public void Generic_InterfaceId_Test()
        {
            var expected = GrainInterfaceUtils.GetGrainInterfaceId(typeof(ISimpleGenericGrain <>));
            IDictionary <int, Type> actual = GrainInterfaceUtils.GetRemoteInterfaces(typeof(SimpleGenericGrain <>));

            Assert.Contains(expected, actual);
        }
Exemple #2
0
        public void Generic_InterfaceId_Test()
        {
            var expected = GrainInterfaceUtils.GetGrainInterfaceId(typeof(ISimpleGenericGrain <>));
            var actual   = GrainInterfaceUtils.GetRemoteInterfaces(typeof(SimpleGenericGrain <>));

            Assert.Single(actual);
            Assert.Equal(expected, GrainInterfaceUtils.GetGrainInterfaceId(actual[0]));
        }
        private IGrainExtensionMethodInvoker TryGetExtensionInvoker(Type handlerType)
        {
            var interfaces = GrainInterfaceUtils.GetRemoteInterfaces(handlerType).Values;
            if (interfaces.Count != 1)
                throw new InvalidOperationException($"Extension type {handlerType.FullName} implements more than one grain interface.");

            var interfaceId = GrainInterfaceUtils.GetGrainInterfaceId(interfaces.First());
            var invoker = typeManager.GetInvoker(interfaceId);
            if (invoker != null)
                return (IGrainExtensionMethodInvoker)invoker;

            throw new ArgumentException(
                $"Provider extension handler type {handlerType} was not found in the type manager",
                nameof(handlerType));
        }
        /// <summary>
        /// Maps the provided <paramref name="interfaceId"/> to the provided <paramref name="implementationType"/>.
        /// </summary>
        /// <param name="interfaceType">The interface type.</param>
        /// <param name="implementationType">The implementation type.</param>
        /// <returns>The mapped interface.</returns>
        private static IReadOnlyDictionary <int, MethodInfo> GetInterfaceToImplementationMap(
            int interfaceId,
            Type implementationType)
        {
            // Get the interface mapping for the current implementation.
            var interfaceTypes   = GrainInterfaceUtils.GetRemoteInterfaces(implementationType);
            var interfaceType    = interfaceTypes[interfaceId];
            var interfaceMapping = implementationType.GetInterfaceMap(interfaceType);

            // Map the interface methods to implementation methods.
            var interfaceMethods = GrainInterfaceUtils.GetMethods(interfaceType);

            return(interfaceMethods.ToDictionary(
                       GrainInterfaceUtils.ComputeMethodId,
                       interfaceMethod => GetImplementingMethod(interfaceMethod, interfaceMapping)));
        }
        /// <summary>
        /// Maps the provided <paramref name="interfaceId"/> to the provided <paramref name="implementationType"/>.
        /// </summary>
        /// <param name="interfaceId">The interface id.</param>
        /// <param name="implementationType">The implementation type.</param>
        /// <returns>The mapped interface.</returns>
        private static Dictionary <int, MethodInfo> GetInterfaceToImplementationMap(
            int interfaceId,
            Type implementationType)
        {
            var interfaceTypes = GrainInterfaceUtils.GetRemoteInterfaces(implementationType);

            // Get all interface mappings of all interfaces.
            var interfaceMapping = implementationType
                                   .GetInterfaces()
                                   .Select(i => implementationType.GetTypeInfo().GetRuntimeInterfaceMap(i))
                                   .SelectMany(map => map.InterfaceMethods
                                               .Zip(map.TargetMethods, (interfaceMethod, targetMethod) => new { interfaceMethod, targetMethod }))
                                   .ToArray();

            // Map the grain interface methods to the implementation methods.
            return(GrainInterfaceUtils.GetMethods(interfaceTypes[interfaceId])
                   .ToDictionary(GrainInterfaceUtils.ComputeMethodId,
                                 m => interfaceMapping.SingleOrDefault(pair => pair.interfaceMethod == m)?.targetMethod));
        }
        /// <summary>
        /// Generates switch cases for the provided grain type.
        /// </summary>
        /// <param name="grainType">
        /// The grain type.
        /// </param>
        /// <param name="methodIdArgument">
        /// The method id argument, which is used to select the correct switch label.
        /// </param>
        /// <param name="generateMethodHandler">
        /// The function used to generate switch block statements for each method.
        /// </param>
        /// <returns>
        /// The switch cases for the provided grain type.
        /// </returns>
        public static SwitchSectionSyntax[] GenerateGrainInterfaceAndMethodSwitch(
            Type grainType,
            ExpressionSyntax methodIdArgument,
            Func <MethodInfo, StatementSyntax[]> generateMethodHandler)
        {
            var interfaces = GrainInterfaceUtils.GetRemoteInterfaces(grainType);

            interfaces[GrainInterfaceUtils.GetGrainInterfaceId(grainType)] = grainType;

            // Switch on interface id.
            var interfaceCases = new List <SwitchSectionSyntax>();

            foreach (var @interface in interfaces)
            {
                var interfaceType = @interface.Value;
                var interfaceId   = @interface.Key;
                var methods       = GrainInterfaceUtils.GetMethods(interfaceType);

                var methodCases = new List <SwitchSectionSyntax>();

                // Switch on method id.
                foreach (var method in methods)
                {
                    // Generate switch case.
                    var methodId   = GrainInterfaceUtils.ComputeMethodId(method);
                    var methodType = method;

                    // Generate the switch label for this interface id.
                    var methodIdSwitchLabel =
                        SF.CaseSwitchLabel(
                            SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId)));

                    // Generate the switch body.
                    var methodInvokeStatement = generateMethodHandler(methodType);

                    methodCases.Add(
                        SF.SwitchSection().AddLabels(methodIdSwitchLabel).AddStatements(methodInvokeStatement));
                }

                // Generate the switch label for this interface id.
                var interfaceIdSwitchLabel =
                    SF.CaseSwitchLabel(
                        SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId)));

                // Generate the default case, which will throw a NotImplementedException.
                var errorMessage = SF.BinaryExpression(
                    SyntaxKind.AddExpression,
                    "interfaceId=".GetLiteralExpression(),
                    SF.BinaryExpression(
                        SyntaxKind.AddExpression,
                        SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId)),
                        SF.BinaryExpression(
                            SyntaxKind.AddExpression,
                            ",methodId=".GetLiteralExpression(),
                            methodIdArgument)));
                var throwStatement =
                    SF.ThrowStatement(
                        SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax())
                        .AddArgumentListArguments(SF.Argument(errorMessage)));
                var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement);

                // Generate switch statements for the methods in this interface.
                var methodSwitchStatements =
                    SF.SwitchStatement(methodIdArgument).AddSections(methodCases.ToArray()).AddSections(defaultCase);

                // Generate the switch section for this interface.
                interfaceCases.Add(
                    SF.SwitchSection().AddLabels(interfaceIdSwitchLabel).AddStatements(methodSwitchStatements));
            }

            return(interfaceCases.ToArray());
        }