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; }
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; }