Exemple #1
0
        public ObjCMethod(Net2ObjC n2c, MethodFacet facet, Dictionary <string, object> options = null)
        {
            // In order to ensure compilation of an assembly and its references
            // the generated code must resolve all types.
            //
            // The generation of a complete set of methods is obviously desirable
            // but in some cases may not be achievable if a unique method signature
            // cannot be obtained.

            // if the method is a duplicate (ie: name, parameter types, return type)
            // then we have no option but to omit it
            if (facet.IsDuplicateSignatureMethod)
            {
                n2c.Warning("Duplicate method omitted : " + facet.Name);
                return;
            }

            // if the facet is overloaded on its signature and differs only in its
            // return type then omit it.
            // This can occur with explicit operators.
            // At present it is unknown if these can be called via the embedded API.
            if (facet.IsOverloadedSignatureMethod)
            {
                n2c.Warning("Overloaded signature method omitted : " + facet.Name);
                return;
            }

            string objCMethodInvokeFormat  = null;
            string objCMethodPrepareFormat = null;

            IsConstructorMethod = (facet.Name == null);    // constructor has no method name
            ObjCMethodType      = null;

            // Method name. We do some rudimentary processing to prevent troublesome behaviour.
            // We may have to prefix certain method names to conform to ARC's semantics
            // see https://stackoverflow.com/questions/22529454/simple-rules-for-naming-methods-compatible-with-arc-naming-conventions
            MonoMethodName = facet.Name;
            ObjCMethodName = MonoMethodName.FirstCharacterToLower();
            if (facet.IsStatic || IsConstructorMethod)
            {
                ObjCMethodType = "+";
                if (facet.Parameters.Count == 0)
                {
                    // decorate class method names known to be unsafe
                    if (n2c.UnsafeObjCClassMethodNames.Contains(ObjCMethodName))
                    {
                        ObjCMethodName += "_";
                    }
                }
            }
            else
            {
                ObjCMethodType = "-";

                // decorate instance method names known to be unsafe
                if (facet.Type != "System.Void" && n2c.UnsafeObjCMethodNames().Any(p => ObjCMethodName.StartsWith(p, false, null)))
                {
                    ObjCMethodName = "db_" + ObjCMethodName;
                }
            }

            // Get ObjC declaration for method return type.
            // In general we want to allow the type association mechanism to substitute
            // native objC types for managed types where appropriate.
            // For example: a managed method that returns a System_DateTime results in an native method that returns an NSDate *.
            // However, when defining a constructor we don't want to permit this association to occur as the constructor
            // won't then contruct a managed instance at all.
            ObjCTypeDecl = n2c.ObjCTypeDeclFromManagedFacet(facet, !IsConstructorMethod);
            if (facet.IsInterface)
            {
                ObjCTypeDecl = n2c.ObjCConformingTypeFromObjCTypeDecl(ObjCTypeDecl, true);
            }

            ManagedValueToObjC = null;

            // instance method requires a name and type
            if (!IsConstructorMethod)
            {
                // create Obj-C representation of mono object
                ManagedValueToObjC = n2c.ManagedValueToObjc(ManagedVariableName, facet);

                // invocation statement
                if (facet.IsGenericMethodDefinition)
                {
                    // generic method definitions require additional type processing prior to invocation.
                    // DBManagedMethod co-ordinates this.
                    if (facet.IsStatic)
                    {
                        // invoke class method
                        objCMethodPrepareFormat = "DBManagedMethod *method = [self classMethodWithMonoName:\"{0}({1})\" typeParameters:typeParameter]";
                        objCMethodInvokeFormat  = "[method invokeClassMethodWithNumArgs:{2}]";
                    }
                    else
                    {
                        objCMethodPrepareFormat = "DBManagedMethod *method = [self methodWithMonoName:\"{0}({1})\" typeParameters:typeParameter]";
                        objCMethodInvokeFormat  = "[method invokeMethodWithNumArgs:{2}]";
                    }
                }
                else
                {
                    if (facet.IsStatic)
                    {
                        // invoke mono class method
                        objCMethodInvokeFormat = "[self invokeMonoClassMethod:\"{0}({1})\" withNumArgs:{2}]";
                    }
                    else
                    {
                        // invoke mono instance method
                        objCMethodInvokeFormat = "[self invokeMonoMethod:\"{0}({1})\" withNumArgs:{2}]";
                    }
                }
            }
            else
            {
                // this looks like a default constructor
                if (facet.Parameters.Count() == 0)
                {
                    return;
                }

                ObjCMethodName = "new";

                // a constructor requires no explicit name or type
                objCMethodInvokeFormat = "[[self alloc] initWithSignature:\"{1}\" withNumArgs:{2}]";
            }

            // process the parameters
            ProcessParameters(n2c, facet, options);

            // a generic method definition will require an additional parameter to specify the generic type parameters
            if (facet.IsGenericMethodDefinition)
            {
                // get number of generic type parameters defined by the generic method definition as opposed to by the type defining the method
                int    numberOfTypeParametersDeclaredByMethod = facet.GenericMethodDefinitionGenericTypeArguments.Count();
                string parameterSig = "typeParameter:(id)typeParameter";
                if (numberOfTypeParametersDeclaredByMethod > 1)
                {
                    parameterSig = "typeParameters:(NSArray<id> *)typeParameter";
                }
                if (facet.Parameters.Count() == 0)
                {
                    ObjCMethodName += "_with";
                    ObjCParameterBuilder.AppendFormat("{0}", parameterSig.FirstCharacterToUpper());
                }
                else
                {
                    ObjCParameterBuilder.AppendFormat(" {0}", parameterSig);
                }
            }

            // finalize argument list representations
            string monoMethodSig = MonoSigBuilder.ToString();

            ObjCMethodParameters = ObjCParameterBuilder.ToString();
            string invokeArgs = facet.Parameters.Count().ToString();

            if (facet.Parameters.Count() > 0)
            {
                invokeArgs += ", " + InvokeArgsBuilder.ToString();
            }

            // form mono method invocation name.
            // a prefix may be required, for instance when calling explicit interface methods.
            string monoMethodPrefix = "";

            if (options != null)
            {
                if (options.ContainsKey("cAPIMethodPrefix"))
                {
                    monoMethodPrefix = (string)options["cAPIMethodPrefix"];
                }
            }
            string monoInvocationName = monoMethodPrefix + MonoMethodName;

            // we may have an expression that prepares the get expression method argument
            if (objCMethodPrepareFormat != null)
            {
                string expression = String.Format(objCMethodPrepareFormat, monoInvocationName, monoMethodSig, invokeArgs) + ";";
                ReferencePreProcessBuilder.AppendFormat("{0}{1}", expression, Environment.NewLine);
            }

            // the get expression invokes the method and gets the result
            GetExpression = String.Format(objCMethodInvokeFormat, monoInvocationName, monoMethodSig, invokeArgs);

            // validation
            if (IsConstructorMethod && String.IsNullOrEmpty(monoMethodSig))
            {
                throw new Exception("Mono method argument signature is empty");
            }
            if (String.IsNullOrEmpty(ObjCTypeDecl))
            {
                throw new Exception("ObjC type Declaration is empty");
            }
            if (String.IsNullOrEmpty(ObjCMethodName))
            {
                throw new Exception("Method name is empty");
            }
            if (String.IsNullOrEmpty(GetExpression))
            {
                throw new Exception("Get expression is empty");
            }

            IsValid = true;
        }
Exemple #2
0
        public ObjCAccessor(Net2ObjC n2c, CodeFacet facet, Dictionary<string, object> options = null)
        {

            Name = facet.Name;
            Description = facet is PropertyFacet ? "property" : "field";

            // define getters and setters
            GetterName = Name.FirstCharacterToLower();
            SetterName = "set" + Name.FirstCharacterToUpper();
            ObjCMethodType = null;
            if (facet.IsStatic) {
                ObjCMethodType = "+";

                // decorate class accessor method names known to be unsafe
                if (n2c.UnsafeObjCClassMethodNames.Contains(GetterName)) {
                    GetterName += "_";
                    SetterName += "_";
                }
            } else {
                ObjCMethodType = "-";
            }

            string accessorType = facet.Type;
            ObjCTypeDecl = n2c.ObjCTypeDeclFromManagedFacet(facet);
            IsObjectProperty = n2c.ObjCRepresentationIsObject(facet);
            MonoObjectPtr = "MonoObject *";
            VoidPtr = "void *";

            // some NSObject properties need a bit of TLC
            BaseProperties = new List<string> { "description" };

            // property storage and evaluation
            PropertyAttributes = "";
            PropertyStorage = "_" + GetterName;
            if (facet.IsStatic) {
                PropertyStorage = "m" + PropertyStorage;
                if (IsObjectProperty) {
                    n2c.StaticObjectPropertyStorageNames.Add(PropertyStorage);
                }
            }
            DoPropertyEqualityTest = "";
            if (IsObjectProperty) {
                // test if mono object pointer and property storage reference the same managed object
                DoPropertyEqualityTest = string.Format("if ([self object:{0} isEqualToMonoObject:{1}]) return {0};", PropertyStorage, ManagedVariableName);
            }

            // instance property.
            if (!facet.IsStatic) {
                string attributes = "nonatomic";

                // object property attributes
                if (n2c.ObjCRepresentationIsObject(facet)) {
                    attributes += ", strong";
                }
                if (!facet.IsWritable) {
                    attributes += ", readonly";
                }
                PropertyAttributes = String.Format("({0}) ", attributes);
            }

            // create Obj-C representation of managed object
            ManagedValueToObjC = n2c.ManagedValueToObjc(ManagedVariableName, facet);
            ObjCValueToMono = n2c.ObjCValueToManaged(ObjCVariableName, ObjCTypeDecl, facet);
            ObjCTypeAssociation objCTypeAssociate = n2c.ObjCTypeAssociate(facet);

            // form mono method invocation name.
            // a prefix may be required, for instance when calling explicit interface properties.
            string monoMethodPrefix = "";
            if (options != null) {
                if (options.ContainsKey("cAPIMethodPrefix")) {
                    monoMethodPrefix = (string)options["cAPIMethodPrefix"];
                }
            }
            MonoInvocationName = monoMethodPrefix + Name;

            IsValid = true;
        }