예제 #1
0
    /// <summary>
    /// Create a singleton field used to store property information for the provided property.
    /// </summary>
    /// <param name="property">The property weaver.</param>
    /// <returns></returns>
    public Variable CreatePropertyInfo(PropertyEmitter property)
    {
        var parent = property.Parent.Target.IsNotPublic ? property.Parent : CreateTypeContainer(property.Parent.Target);
        var type   = property.Parent.Target;
        var sta    = (property.Target.GetMethod ?? property.Target.SetMethod).IsStatic;
        var name   = $"<{property.Target.Name}>k__PropertyInfo";

        var existing = parent.GetField(name, Context.Finder.PropertyInfo, toStatic: true);

        if (existing != null)
        {
            return(existing);
        }

        var field = parent.EmitField(name, Context.Finder.PropertyInfo, toStatic: true, toPublic: true);
        var flags = BindingFlags.NonPublic | BindingFlags.Public | (sta ? BindingFlags.Static : BindingFlags.Instance);

        var il = parent.GetStaticConstructor().GetIL();

        il.Emit(Codes.Nop);
        il.Emit(Codes.LoadToken(type.GetGeneric()));
        il.Emit(Codes.InvokeStatic(Context.Finder.TypeGetTypeFromHandle));
        il.Emit(Codes.String(property.Target.Name));
        il.Emit(Codes.Int((int)flags));
        il.Emit(Codes.Invoke(Context.Finder.TypeGetProperty));
        il.Emit(Codes.Store(field));

        return(field);
    }
예제 #2
0
        void EventEmit(IViewEvent viewEvent, List <MemberEmitter> ret)
        {
            string name        = viewEvent.Name.Replace("/", "").Replace(".", "");
            string genericType = (viewEvent.EventType() != null) ? $"<{GetTypeString(viewEvent.EventType())}>" : "";

            PropertyEmitter property = new PropertyEmitter();

            property.Name    = "On" + name;
            property.Type    = "event Action" + genericType;
            property.Summary = $"BindingPath : {viewEvent.Name}\nSender: {viewEvent.ToString()}";

            property.Getter = new DelegateEmitter(w =>
            {
                w.WriteLine("add");
                using (w.Bracket())
                {
                    w.WriteLine($"m_Event.Subscribe{genericType}(\"{viewEvent.Name}\", value);");
                }
            });
            property.Setter = new DelegateEmitter(w =>
            {
                w.WriteLine("remove");
                using (w.Bracket())
                {
                    w.WriteLine($"m_Event.Unsubscribe{genericType}(\"{viewEvent.Name}\", value);");
                }
            });
            ret.Add(property);
        }
예제 #3
0
    /// <summary>
    /// Weaves an implementation of a property against the provided type.
    /// </summary>
    /// <param name="emitter">The emitter.</param>
    /// <param name="field">The attribute field.</param>
    /// <param name="property">The property.</param>
    /// <param name="interfaceType">The type of the interface.</param>
    public void WeaveImplementedProperty(TypeEmitter emitter, Variable field, PropertyDefinition property, TypeDefinition interfaceType)
    {
        var emitted     = emitter.EmitProperty(property.Name, property.PropertyType.Import(), toBackingField: true);
        var implemented = field.Type.GetProperty(property.Name, property.PropertyType)?.Resolve();

        if (implemented == null)
        {
            implemented = field.Type.GetProperty($"{interfaceType.FullName}.{property.Name}", returnType: property.PropertyType)?.Resolve();

            if (implemented == null)
            {
                throw new MissingMemberException($"Cannot implement '{field.Type.FullName}' as it does not implement property '{property.Name}'");
            }
        }

        var source = new PropertyEmitter(emitter, implemented);

        if (source.HasGetter && !emitted.HasGetter)
        {
            var getter      = emitted.GetGetter();
            var il          = getter.GetIL();
            var propertyGet = property.GetMethod?.Import() ?? implemented.GetMethod.Import();

            getter.Body.SimplifyMacros();

            il.Emit(Codes.Nop);
            il.Emit(Codes.ThisIf(field));
            il.Emit(Codes.Cast(interfaceType));
            il.Emit(Codes.Load(field));
            il.Emit(Codes.Invoke(propertyGet.GetGeneric()));
            il.Emit(Codes.Return);

            getter.Body.OptimizeMacros();
            getter.Body.InitLocals = true;
        }

        if (source.HasSetter && !emitted.HasSetter)
        {
            var setter      = emitted.GetSetter();
            var il          = setter.GetIL();
            var propertySet = property.SetMethod?.Import() ?? implemented.SetMethod.Import();

            setter.Body.SimplifyMacros();

            il.Emit(Codes.Nop);
            il.Emit(Codes.ThisIf(field));
            il.Emit(Codes.Load(field));
            il.Emit(Codes.Arg(setter.Target.IsStatic ? 0 : 1));
            il.Emit(Codes.Invoke(propertySet.GetGeneric()));
            il.Emit(Codes.Return);

            setter.Body.OptimizeMacros();
            setter.Body.InitLocals = true;
        }
    }
예제 #4
0
    /// <summary>
    /// Create an attribute variable for a property definition.
    /// </summary>
    /// <param name="property">The property.</param>
    /// <param name="get">The getter method.</param>
    /// <param name="set">The setter method.</param>
    /// <param name="attribute">The attribute.</param>
    /// <param name="field">The optional field reference which was routed.</param>
    /// <returns></returns>
    public Variable[] CreateAttribute(PropertyEmitter property, MethodEmitter get, MethodEmitter set, CustomAttribute attribute, MemberReference field)
    {
        var method = get ?? set;
        var sta    = method.Target.IsStatic;

        var options = attribute.GetAttribute(Context.Finder.CompilationOptionsAttribute);
        var scope   = options.GetProperty("Scope", notFound: AttributeScopeSingleton);

        if (sta)
        {
            if (scope == AttributeScopeInstanced)
            {
                scope = AttributeScopeSingleton;
            }
            else if (scope == AttributeScopeMultiInstanced)
            {
                scope = AttributeScopeMultiSingleton;
            }
        }

        var hasGet = attribute.HasInterface(Context.Finder.IPropertyGetInterceptor);
        var hasSet = attribute.HasInterface(Context.Finder.IPropertySetInterceptor);

        switch (scope)
        {
        case AttributeScopeAdhoc:
            var adhocGet = hasGet && get != null?CreateAttributeAdhoc(get, attribute, property.Target) : null;

            var adhocSet = hasSet && set != null?CreateAttributeAdhoc(set, attribute, property.Target) : null;

            return(new[] { adhocGet, adhocSet });

        case AttributeScopeInstanced:
            var instanced = CreateAttributeInstanced(property.Parent, attribute, field ?? property.Target);
            return(new[] { hasGet?instanced : null, hasSet ? instanced : null });

        case AttributeScopeMultiInstanced:
            var multi = CreateAttributeMultiInstanced(property.Parent, attribute, field ?? property.Target);
            return(new[] { hasGet?multi : null, hasSet ? multi : null });

        case AttributeScopeSingleton:
            var singleton = CreateAttributeSingleton(property.Parent, attribute, field ?? property.Target);
            return(new[] { hasGet?singleton : null, hasSet ? singleton : null });

        case AttributeScopeMultiSingleton:
            var multiSingleton = CreateAttributeMultiSingleton(property.Parent, attribute, field ?? property.Target);
            return(new[] { hasGet?multiSingleton : null, hasSet ? multiSingleton : null });

        default:
            throw new NotSupportedException($"Cannot create attribute '{attribute.AttributeType.FullName}' with scope '{scope}'");
        }
    }
예제 #5
0
        public void BuildPropertyEmitter(ClassEmitter classEmitter)
        {
            if (emitter != null)
            {
                throw new InvalidOperationException("Emitter is already created. It is illegal to invoke this method twice.");
            }

            emitter = classEmitter.CreateProperty(name, attributes, type, arguments);
            foreach (var attribute in customAttributes)
            {
                emitter.DefineCustomAttribute(attribute);
            }
        }
예제 #6
0
        void PropertyEmit(IBindable bindable, List <MemberEmitter> ret)
        {
            PropertyEmitter property = new PropertyEmitter();
            string          name     = bindable.Path.Replace("/", "").Replace(".", "");

            if (bindable is IViewEvent)
            {
                name += m_Config.EventValueSuffix;
            }
            string type = GetTypeString(bindable.BindType());

            property.Name    = name;
            property.Type    = type;
            property.Setter  = new WriteLineEmitter($"set {{ SetImpl<{type}>(\"{bindable.Path}\", value); }}");
            property.Getter  = new WriteLineEmitter($"get {{ return GetImpl<{type}>(\"{bindable.Path}\"); }}");
            property.Summary = $"BindingPath : {bindable.Path}\nTarget: {bindable.ToString()}";
            ret.Add(property);
        }
        public static PropertyDefinition ChangeToProperty(this FieldDefinition field)
        {
            var emitter = new PropertyEmitter(field.Name, field.FieldType, field.DeclaringType,
                                              getterAttributes: MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName,
                                              setterAttributes: MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName
                                              );

            field.Name      = field.GetBackingName();
            field.IsPublic  = false;
            field.IsPrivate = true;

            field.CustomAttributes.Add(new CustomAttribute(
                                           field.DeclaringType.Module.ImportReference(
                                               typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)
                                               .GetConstructors()
                                               .Single()
                                               )
                                           ));

            return(emitter.Emit());
        }
예제 #8
0
        void CommandEmit(IViewEvent viewEvent, List <MemberEmitter> ret)
        {
            string name        = viewEvent.Name.Replace("/", "").Replace(".", "");
            string genericType = (viewEvent.EventType() != null) ? $"<{GetTypeString(viewEvent.EventType())}>" : "";

            FieldEmitter field = new FieldEmitter();

            field.Accessibility = "private";
            field.Name          = "m_" + name + m_Config.CommandSuffix;
            field.Type          = "BindingCommand" + genericType;
            ret.Add(field);


            PropertyEmitter property = new PropertyEmitter();

            property.Name    = name + m_Config.CommandSuffix;
            property.Type    = "ICommand" + genericType;
            property.Summary = $"BindingPath : {viewEvent.Name}\nSender: {viewEvent.ToString()}";

            property.Getter = new DelegateEmitter(w =>
            {
                w.WriteLine("get");
                using (w.Bracket())
                {
                    w.WriteLine($"return m_{name}{m_Config.CommandSuffix}?.Get() ?? null;");
                }
            });
            property.Setter = new DelegateEmitter(w =>
            {
                w.WriteLine("set");
                using (w.Bracket())
                {
                    w.WriteLine($"if (m_{name}{m_Config.CommandSuffix} == null) m_{name}{m_Config.CommandSuffix} = new BindingCommand{genericType}(\"{viewEvent.Name}\", this);");
                    w.WriteLine($"m_{name}{m_Config.CommandSuffix}.Set(value);");
                }
            });
            ret.Add(property);
        }
예제 #9
0
 private static Type CreateProxyType(Type interfaceType)
 {
     if (!interfaceType.IsInterface) {
         throw new ArgumentException("Only interfaces can be proxied", "interfaceType");
     }
     string name = string.Format("Proxy<{0}>", Regex.Replace(interfaceType.AssemblyQualifiedName ?? interfaceType.FullName ?? interfaceType.Name, @"[\s,]+", "_"));
     List<Type> allInterfaces = new List<Type> {
                                               		interfaceType
                                               };
     allInterfaces.AddRange(interfaceType.GetInterfaces());
     Debug.WriteLine(name, "Emitting proxy type");
     TypeBuilder typeBuilder = proxyModule.DefineType(name, TypeAttributes.Class|TypeAttributes.Sealed|TypeAttributes.Public, typeof(ProxyBase), allInterfaces.ToArray());
     ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
     ILGenerator ctorIl = constructorBuilder.GetILGenerator();
     ctorIl.Emit(OpCodes.Ldarg_0);
     ctorIl.Emit(OpCodes.Call, proxyBase_ctor);
     ctorIl.Emit(OpCodes.Ret);
     FieldBuilder propertyChangedField = null;
     if (typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType)) {
         propertyChangedField = typeBuilder.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private);
         MethodBuilder addPropertyChangedMethod = typeBuilder.DefineMethod("add_PropertyChanged", MethodAttributes.Public|MethodAttributes.HideBySig|MethodAttributes.SpecialName|MethodAttributes.NewSlot|MethodAttributes.Virtual, typeof(void), new[] {typeof(PropertyChangedEventHandler)});
         ILGenerator addIl = addPropertyChangedMethod.GetILGenerator();
         addIl.Emit(OpCodes.Ldarg_0);
         addIl.Emit(OpCodes.Dup);
         addIl.Emit(OpCodes.Ldfld, propertyChangedField);
         addIl.Emit(OpCodes.Ldarg_1);
         addIl.Emit(OpCodes.Call, delegate_Combine);
         addIl.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
         addIl.Emit(OpCodes.Stfld, propertyChangedField);
         addIl.Emit(OpCodes.Ret);
         MethodBuilder removePropertyChangedMethod = typeBuilder.DefineMethod("remove_PropertyChanged", MethodAttributes.Public|MethodAttributes.HideBySig|MethodAttributes.SpecialName|MethodAttributes.NewSlot|MethodAttributes.Virtual, typeof(void), new[] {typeof(PropertyChangedEventHandler)});
         ILGenerator removeIl = removePropertyChangedMethod.GetILGenerator();
         removeIl.Emit(OpCodes.Ldarg_0);
         removeIl.Emit(OpCodes.Dup);
         removeIl.Emit(OpCodes.Ldfld, propertyChangedField);
         removeIl.Emit(OpCodes.Ldarg_1);
         removeIl.Emit(OpCodes.Call, delegate_Remove);
         removeIl.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
         removeIl.Emit(OpCodes.Stfld, propertyChangedField);
         removeIl.Emit(OpCodes.Ret);
         typeBuilder.DefineMethodOverride(addPropertyChangedMethod, iNotifyPropertyChanged_PropertyChanged.GetAddMethod());
         typeBuilder.DefineMethodOverride(removePropertyChangedMethod, iNotifyPropertyChanged_PropertyChanged.GetRemoveMethod());
     }
     List<PropertyInfo> propertiesToImplement = new List<PropertyInfo>();
     // first we collect all properties, those with setters before getters in order to enable less specific redundant getters
     foreach (PropertyInfo property in allInterfaces.Where(intf => intf != typeof(INotifyPropertyChanged)).SelectMany(intf => intf.GetProperties())) {
         if (property.CanWrite) {
             propertiesToImplement.Insert(0, property);
         } else {
             propertiesToImplement.Add(property);
         }
     }
     Dictionary<string, PropertyEmitter> fieldBuilders = new Dictionary<string, PropertyEmitter>();
     foreach (PropertyInfo property in propertiesToImplement) {
         PropertyEmitter propertyEmitter;
         if (fieldBuilders.TryGetValue(property.Name, out propertyEmitter)) {
             if ((propertyEmitter.PropertyType != property.PropertyType) && ((property.CanWrite) || (!property.PropertyType.IsAssignableFrom(propertyEmitter.PropertyType)))) {
                 throw new ArgumentException(string.Format("The interface has a conflicting property {0}", property.Name), "interfaceType");
             }
         } else {
             fieldBuilders.Add(property.Name, propertyEmitter = new PropertyEmitter(typeBuilder, property.Name, property.PropertyType, propertyChangedField));
         }
         if (property.CanRead) {
             typeBuilder.DefineMethodOverride(propertyEmitter.GetGetter(property.PropertyType), property.GetGetMethod());
         }
         if (property.CanWrite) {
             typeBuilder.DefineMethodOverride(propertyEmitter.GetSetter(property.PropertyType), property.GetSetMethod());
         }
     }
     return typeBuilder.CreateType();
 }
        /// <summary>
        /// The method to be called to create the property level attributes for the PropertyEmitter
        /// </summary>
        /// <param name="emitter">The strongly typed emitter</param>
        /// <param name="propertyDecl">The type declaration to add the attribues to.</param>
        /// <param name="additionalAttributes">Additional attributes to emit</param>
        public void EmitPropertyAttributes(PropertyEmitter emitter,
                                           CodeMemberProperty propertyDecl,
                                           List<CodeAttributeDeclaration> additionalAttributes)
        {
            if (MetadataUtil.IsPrimitiveType(emitter.Item.TypeUsage.EdmType) || MetadataUtil.IsEnumerationType(emitter.Item.TypeUsage.EdmType))
            {
                CodeAttributeDeclaration scalarPropertyAttribute = EmitSimpleAttribute(FQAdoFrameworkDataClassesName("EdmScalarPropertyAttribute"));

                if (emitter.IsKeyProperty)
                {
                    Debug.Assert(emitter.Item.Nullable == false, "An EntityKeyProperty cannot be nullable.");

                    AttributeEmitter.AddNamedAttributeArguments(scalarPropertyAttribute, "EntityKeyProperty", true);
                }

                if (!emitter.Item.Nullable)
                {
                    AttributeEmitter.AddNamedAttributeArguments(scalarPropertyAttribute, "IsNullable", false);
                }

                propertyDecl.CustomAttributes.Add(scalarPropertyAttribute);
            }
            else //Complex property
            {
                Debug.Assert(MetadataUtil.IsComplexType(emitter.Item.TypeUsage.EdmType) ||
                             (MetadataUtil.IsCollectionType(emitter.Item.TypeUsage.EdmType)),
                             "not a complex type or a collection type");
                CodeAttributeDeclaration attribute = EmitSimpleAttribute(FQAdoFrameworkDataClassesName("EdmComplexPropertyAttribute"));
                propertyDecl.CustomAttributes.Add(attribute);

                // Have CodeDOM serialization set the properties on the ComplexObject, not the ComplexObject instance.
                attribute = EmitSimpleAttribute("System.ComponentModel.DesignerSerializationVisibility");
                AttributeEmitter.AddAttributeArguments(attribute,
                    new object[] { new CodePropertyReferenceExpression(
                        new CodeTypeReferenceExpression(TypeReference.ForType(
                            typeof(System.ComponentModel.DesignerSerializationVisibility))),"Content") });
                propertyDecl.CustomAttributes.Add(attribute);

                if (!MetadataUtil.IsCollectionType(emitter.Item.TypeUsage.EdmType))
                {
                    // Non-collection complex properties also need additional serialization attributes to force them to be explicitly serialized if they are null
                    // If this is omitted, null complex properties do not get explicitly set to null during deserialization, which causes
                    // them to be lazily constructed once the property is accessed after the entity is deserialized. If the property is
                    // actually null during serialiation, that means the user has explicitly set it, so we need to maintain that during serialization.
                    // This doesn't apply to collection types because they aren't lazily constructed and don't need this extra information.
                    attribute = EmitSimpleAttribute("System.Xml.Serialization.XmlElement");
                    AttributeEmitter.AddNamedAttributeArguments(attribute, "IsNullable", true);
                    propertyDecl.CustomAttributes.Add(attribute);

                    attribute = EmitSimpleAttribute("System.Xml.Serialization.SoapElement");
                    AttributeEmitter.AddNamedAttributeArguments(attribute, "IsNullable", true);
                    propertyDecl.CustomAttributes.Add(attribute);
                }

            }

            // serialization attribute
            AddDataMemberAttribute(propertyDecl);            

            if (additionalAttributes != null && additionalAttributes.Count > 0)
            {
                try
                {
                    propertyDecl.CustomAttributes.AddRange(additionalAttributes.ToArray());
                }
                catch (ArgumentNullException e)
                {
                    emitter.Generator.AddError(Strings.InvalidAttributeSuppliedForProperty(emitter.Item.Name),
                                               ModelBuilderErrorCode.InvalidAttributeSuppliedForProperty,
                                               EdmSchemaErrorSeverity.Error,
                                               e);
                }
            }

            EmitGeneratedCodeAttribute(propertyDecl);
        }
예제 #11
0
 /// <summary>
 /// The method to be called to create the property level attributes for the PropertyEmitter
 /// </summary>
 /// <param name="emitter">The strongly typed emitter</param>
 /// <param name="propertyDecl">The type declaration to add the attribues to.</param>
 /// <param name="additionalAttributes">Additional attributes to emit</param>
 public void EmitPropertyAttributes(PropertyEmitter emitter,
                                    CodeMemberProperty propertyDecl,
                                    List<CodeAttributeDeclaration> additionalAttributes)
 {
     if (additionalAttributes != null && additionalAttributes.Count > 0)
     {
         try
         {
             propertyDecl.CustomAttributes.AddRange(additionalAttributes.ToArray());
         }
         catch (ArgumentNullException e)
         {
             emitter.Generator.AddError(Strings.InvalidAttributeSuppliedForProperty(emitter.Item.Name),
                                        ModelBuilderErrorCode.InvalidAttributeSuppliedForProperty,
                                        EdmSchemaErrorSeverity.Error,
                                        e);
         }
     }
 }
예제 #12
0
        public Type EmitClass(IEnumerable <Type> interfaceTypes,
                              Type baseType,
                              IEnumerable <MethodInfo> methodsToOverride,
                              IEnumerable <PropertyInfo> propertiesToOverride,
                              IEnumerable <EventInfo> eventsToOverride,
                              ConstructorInfo baseConstructor,
                              IEnumerable <CustomAttributeBuilder> attributeBuilders)
        {
            // Apply default values for parameters

            if (baseType == null)
            {
                baseType = typeof(EmittedClassBase);
            }

            // Check limitations for this version

            if (baseType != typeof(EmittedClassBase))
            {
                throw new NotImplementedException("The only supported baseType value is 'EmittedClassBase' in this version.");
            }
            if ((interfaceTypes == null) || (interfaceTypes.Count() != 1))
            {
                throw new NotImplementedException(
                          "Current implementation should be provided with exactly one single interface to implement.");
            }

            Type interfaceType = interfaceTypes.Single();

            // Validate arguments

            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException("interfaceTypes can contain 'interface' types only. " + interfaceType.FullName +
                                            " is not an interface.");
            }

            // Check if the component is initialized

            if ((_moduleBuilder == null) || (_assemblyBuilder == null))
            {
                throw new InvalidOperationException("The DefaultClassEmitter component is not initialized properly.");
            }

            var uniqueTypeNumber = Interlocked.Increment(ref _typeNumber);
            var typeName         = DynamicTypePrefix + interfaceType.Name + uniqueTypeNumber;

            var typeBuilder = _moduleBuilder.DefineType(
                typeName,
                TypeAttributes.Public
                | TypeAttributes.Class
                | TypeAttributes.AutoClass
                | TypeAttributes.AnsiClass
                | TypeAttributes.BeforeFieldInit
                | TypeAttributes.AutoLayout,
                typeof(EmittedClassBase),
                new[] { interfaceType });

            // Add custom attributes

            if (attributeBuilders != null)
            {
                foreach (var builder in attributeBuilders)
                {
                    typeBuilder.SetCustomAttribute(builder);
                }
            }

            // Implement properties, events and methods

            foreach (var propertyInfo in interfaceType.GetProperties())
            {
                PropertyEmitter.EmitProperty(typeBuilder, propertyInfo);
            }

            foreach (var eventInfo in interfaceType.GetEvents())
            {
                EventEmitter.EmitEvent(typeBuilder, eventInfo);
            }

            foreach (var methodInfo in interfaceType.GetMethods())
            {
                MethodBuilder methodBuilder = MethodEmitter.EmitMethod(
                    typeBuilder,
                    methodInfo.Name,
                    methodInfo.GetParameters().Select(pi => pi.ParameterType).ToArray(),
                    methodInfo.GetParameters().Select(pi => pi.IsOut).ToArray(),
                    methodInfo.ReturnType,
                    methodInfo.ReflectedType,
                    InterfaceMethodAttributes);

                typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
            }

            var result = typeBuilder.CreateTypeInfo();


//			if (SaveEmittedAssembly)
//				_assemblyBuilder.Save(DynamicAssemblyName + ".dll");

            return(result);
        }
예제 #13
0
        /// <summary>
        /// Emit static factory method which creates an instance of the class and initializes
        /// non-nullable properties (taken as arguments)
        /// </summary>
        /// <param name="typeDecl"></param>
        protected virtual void EmitFactoryMethod(CodeTypeDeclaration typeDecl)
        {
            // build list of non-nullable properties
            ReadOnlyMetadataCollection<EdmProperty> properties = GetProperties();
            List<EdmProperty> parameters = new List<EdmProperty>(properties.Count);
            foreach (EdmProperty property in properties)
            {
                bool include = IncludeFieldInFactoryMethod(property);
                if (include)
                {
                    parameters.Add(property);
                }
            }

            // if there are no parameters, we don't emit anything (1 is for the null element)
            // nor do we emit everything if this is the Ref propertied ctor and the parameter list is the same as the many parametered ctor
            if (parameters.Count < 1)
            {
                return;
            }

            CodeMemberMethod method = new CodeMemberMethod();
            CodeTypeReference typeRef = TypeReference.FromString(Item.Name);
            UniqueIdentifierService uniqueIdentifierService = new UniqueIdentifierService(Generator.IsLanguageCaseSensitive);
            string instanceName = uniqueIdentifierService.AdjustIdentifier(Utils.CamelCase(Item.Name));

            // public static Class CreateClass(...)
            method.Attributes = MemberAttributes.Static | MemberAttributes.Public;
            method.Name = "Create" + Item.Name;
            if (NavigationPropertyEmitter.IsNameAlreadyAMemberName(Item, method.Name, Generator.LanguageAppropriateStringComparer))
            {
                Generator.AddError(Strings.GeneratedFactoryMethodNameConflict(method.Name, Item.Name),
                    ModelBuilderErrorCode.GeneratedFactoryMethodNameConflict,
                    EdmSchemaErrorSeverity.Error);
            }

            method.ReturnType = typeRef;
            AttributeEmitter.AddGeneratedCodeAttribute(method);

            // output method summary comments 
            CommentEmitter.EmitSummaryComments(Strings.FactoryMethodSummaryComment(Item.Name), method.Comments);


            // Class class = new Class();
            CodeVariableDeclarationStatement createNewInstance = new CodeVariableDeclarationStatement(
                typeRef, instanceName, new CodeObjectCreateExpression(typeRef));
            method.Statements.Add(createNewInstance);
            CodeVariableReferenceExpression instanceRef = new CodeVariableReferenceExpression(instanceName);

            // iterate over the properties figuring out which need included in the factory method
            foreach (EdmProperty property in parameters)
            {
                // CreateClass( ... , propType propName ...)
                PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, UsingStandardBaseClass);
                CodeTypeReference propertyTypeReference = propertyEmitter.PropertyType;
                String parameterName = uniqueIdentifierService.AdjustIdentifier(Utils.FixParameterName(propertyEmitter.PropertyName, "argument"));
                parameterName = Utils.SetSpecialCaseForFxCopOnPropertyName(parameterName);
                CodeParameterDeclarationExpression paramDecl = new CodeParameterDeclarationExpression(
                    propertyTypeReference, parameterName);
                CodeArgumentReferenceExpression paramRef = new CodeArgumentReferenceExpression(paramDecl.Name);
                method.Parameters.Add(paramDecl);

                // add comment describing the parameter
                CommentEmitter.EmitParamComments(paramDecl, Strings.FactoryParamCommentGeneral(propertyEmitter.PropertyName), method.Comments);

                CodeExpression newPropertyValue;
                if (TypeSemantics.IsComplexType(propertyEmitter.Item.TypeUsage))
                {
                    List<CodeExpression> complexVerifyParameters = new List<CodeExpression>();
                    complexVerifyParameters.Add(paramRef);
                    complexVerifyParameters.Add(new CodePrimitiveExpression(propertyEmitter.PropertyName));

                    // if (null == param) { throw new ArgumentNullException("PropertyName"); }
                    method.Statements.Add(
                        new CodeConditionStatement(
                            EmitExpressionEqualsNull(paramRef),
                            new CodeThrowExceptionStatement(
                                new CodeObjectCreateExpression(
                                    TypeReference.ForType(typeof(ArgumentNullException)),
                                    new CodePrimitiveExpression(parameterName)
                                )
                            )
                        )
                    );

                    newPropertyValue = paramRef;
                }
                else
                {
                    newPropertyValue = paramRef;
                }

                // Scalar property:
                //     Property = param;
                // Complex property:
                //     Property = StructuralObject.VerifyComplexObjectIsNotNull(param, propertyName);

                method.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(instanceRef, propertyEmitter.PropertyName), newPropertyValue));
            }

            // return class;
            method.Statements.Add(new CodeMethodReturnStatement(instanceRef));

            // actually add the method to the class
            typeDecl.Members.Add(method);
        }
예제 #14
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="typeDecl"></param>
 protected virtual void EmitProperties(CodeTypeDeclaration typeDecl)
 {
     foreach (EdmMember member in Item.Members)
     {
         EdmProperty property = (member as EdmProperty);
         if ((null != property) && (property.DeclaringType == Item))
         {
             PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, _usingStandardBaseClass);
             propertyEmitter.Emit(typeDecl);
         }
     }
 }
예제 #15
0
        public void WithAutoGetterSetter()
        {
            var emiter = new PropertyEmitter(this);

            emiter.EmitAuto();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="typeDecl"></param>
        protected virtual void EmitProperties(CodeTypeDeclaration typeDecl)
        {

            foreach (EdmProperty property in Item.GetDeclaredOnlyMembers<EdmProperty>())
            {
                PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, _usingStandardBaseClass);
                propertyEmitter.Emit(typeDecl);
            }
        }
 public override void EmitProperty(PropertyInfo propertyInfo)
 {
     var emitter = new PropertyEmitter(TypeBuilder, ImplField);
     emitter.Emit(propertyInfo);
 }
예제 #18
0
    /// <summary>
    /// Weaves the interception logic of a property.
    /// </summary>
    /// <param name="parent"></param>
    /// <param name="item"></param>
    public void WeavePropertyInterceptors(TypeEmitter parent, PropertyInterceptorInfo item)
    {
        var property = item.Property;
        var getter   = property.GetMethod != null ? new MethodEmitter(parent, property.GetMethod) : null;
        var setter   = property.SetMethod != null ? new MethodEmitter(parent, property.SetMethod) : null;
        var count    = item.Interceptors.Length;
        var weaver   = new PropertyEmitter(parent, property);

        if (count == 0)
        {
            return;
        }

        var gInterceptors = new Variable[count];
        var sInterceptors = new Variable[count];

        for (int i = 0; i < count; i++)
        {
            var variables = CreateAttribute(weaver, getter, setter, item.Interceptors[i], item.Field);

            gInterceptors[i] = variables[0];
            sInterceptors[i] = variables[1];
        }

        var hasGetter = gInterceptors.Any(i => i != null);
        var hasSetter = sInterceptors.Any(i => i != null);

        var type    = property.PropertyType;
        var info    = CreatePropertyInfo(weaver);
        var field   = property.GetBackingField();
        var backing = (Variable)null;

        if (field != null)
        {
            var def = field.Resolve();

            def.Attributes &= ~Mono.Cecil.FieldAttributes.InitOnly;
            backing         = new Variable(def);
        }

        if (getter != null && hasGetter)
        {
            var il     = getter.GetIL();
            var result = getter.EmitLocal(property.PropertyType);

            il.Body.SimplifyMacros();
            il.Position = il.GetFirst();
            il.Insert   = CodeInsertion.Before;

            if (backing != null)
            {
                il.Emit(Codes.ThisIf(backing));
                il.Emit(Codes.Load(backing));
                il.Emit(Codes.Store(result));
            }
            else
            {
                if (type.IsValueType)
                {
                    il.Emit(Codes.Address(result));
                    il.Emit(Codes.Init(type));
                }
                else
                {
                    il.Emit(Codes.Null);
                    il.Emit(Codes.Store(result));
                }
            }

            il.Try();

            var leave  = WeaveMethodReturnsRoute(getter, result, true);
            var cancel = il.EmitLabel();
            var args   = il.EmitLocal(Context.Finder.PropertyInterceptionArgs);

            il.Emit(getter.Target.IsStatic ? Codes.Null : Codes.This);
            il.Emit(Codes.Load(info));
            il.Emit(Codes.Load(result));
            il.Emit(Codes.Box(type));
            il.Emit(Codes.Create(Context.Finder.PropertyInterceptionArgsCtor));
            il.Emit(Codes.Store(args));

            for (int i = 0; i < count; i++)
            {
                var inc = gInterceptors[i];

                if (inc == null)
                {
                    continue;
                }

                il.Emit(Codes.ThisIf(inc));
                il.Emit(Codes.Load(inc));
                il.Emit(Codes.Load(args));
                il.Emit(Codes.Invoke(Context.Finder.PropertyGetInterceptorOnGet));
            }

            il.Position = leave;
            il.Finally();

            for (int i = 0; i < count; i++)
            {
                var inc = gInterceptors[i];

                if (inc == null)
                {
                    continue;
                }

                il.Emit(Codes.ThisIf(inc));
                il.Emit(Codes.Load(inc));
                il.Emit(Codes.Load(args));
                il.Emit(Codes.Invoke(Context.Finder.PropertyGetInterceptorOnExit));
            }

            il.Mark(cancel);
            il.EndTry();

            il.Insert = CodeInsertion.After;

            if (setter != null || backing != null)
            {
                var unchanged = il.EmitLabel();

                il.Emit(Codes.Load(args));
                il.Emit(Codes.Invoke(Context.Finder.PropertyInterceptionArgsIsDirtyGet));
                il.Emit(Codes.IfFalse(unchanged));

                if (!getter.Target.IsStatic)
                {
                    il.Emit(Codes.This);
                }

                if (backing == null)
                {
                    var pcount = setter.Target.Parameters.Count - 1;

                    for (int i = 0; i < pcount; i++)
                    {
                        il.Emit(Codes.Arg(setter.Target.Parameters[i]));
                    }
                }

                il.Emit(Codes.Load(args));
                il.Emit(Codes.Invoke(Context.Finder.PropertyInterceptionArgsValueGet));
                il.Emit(Codes.Unbox(type));

                if (backing != null)
                {
                    il.Emit(Codes.Store(backing));
                }
                else
                {
                    il.Emit(Codes.Invoke(setter.Target));
                }

                il.Emit(Codes.Load(args));
                il.Emit(Codes.Invoke(Context.Finder.PropertyInterceptionArgsValueGet));
                il.Emit(Codes.Unbox(type));
                il.Emit(Codes.Store(result));

                il.Emit(Codes.Nop);
                il.Mark(unchanged);
            }

            il.Emit(Codes.Load(result));

            il.Body.InitLocals = true;
            il.Body.OptimizeMacros();
        }

        if (setter != null && hasSetter)
        {
            var il = setter.GetIL();

            il.Body.SimplifyMacros();
            il.Position = il.GetFirst();
            il.Insert   = CodeInsertion.Before;

            var args     = il.EmitLocal(Context.Finder.PropertyInterceptionArgs);
            var cancel   = il.EmitLabel();
            var argument = new Variable(setter.Target.Parameters.Last());

            il.Try();

            il.Emit(setter.Target.IsStatic ? Codes.Null : Codes.This);
            il.Emit(Codes.Load(info));
            il.Emit(Codes.Load(argument));
            il.Emit(Codes.Box(type));
            il.Emit(Codes.Create(Context.Finder.PropertyInterceptionArgsCtor));
            il.Emit(Codes.Store(args));

            for (int i = 0; i < count; i++)
            {
                var inc = sInterceptors[i];

                if (inc == null)
                {
                    continue;
                }

                il.Emit(Codes.ThisIf(inc));
                il.Emit(Codes.Load(inc));
                il.Emit(Codes.Load(args));
                il.Emit(Codes.Invoke(Context.Finder.PropertySetInterceptorOnSet));
            }

            il.Emit(Codes.Load(args));
            il.Emit(Codes.Invoke(Context.Finder.PropertyInterceptionArgsIsDirtyGet));
            il.Emit(Codes.IfFalse(cancel));

            il.Emit(Codes.Load(args));
            il.Emit(Codes.Invoke(Context.Finder.PropertyInterceptionArgsValueGet));
            il.Emit(Codes.Unbox(argument.Type));
            il.Emit(Codes.Store(argument));
            il.Emit(Codes.Nop);

            il.Position = il.Position.Previous;
            il.Mark(cancel);

            il.Position = il.GetLast();
            il.Emit(Codes.Leave(il.Position));
            il.Finally();

            for (int i = 0; i < count; i++)
            {
                var inc = sInterceptors[i];

                if (inc == null)
                {
                    continue;
                }

                il.Emit(Codes.ThisIf(inc));
                il.Emit(Codes.Load(inc));
                il.Emit(Codes.Load(args));
                il.Emit(Codes.Invoke(Context.Finder.PropertySetInterceptorOnExit));
            }

            il.EndTry();

            il.Body.InitLocals = true;
            il.Body.OptimizeMacros();
        }
    }