/// <summary> /// Returns whether the type reference is of a type that can be replaced by ObservableCollection{T}. /// </summary> /// <param name="typeReference">The typeReference to check.</param> /// <param name="weavingContext">The weavingContext to use..</param> /// <returns>True when the type is a type that can be replaced by one of the interfaces of ObservableCollection{T}", false otherwise.</returns> public static bool IsReplaceableCollection(this TypeReference typeReference, WeavingContext weavingContext) { if (typeReference is null) { throw new ArgumentNullException(nameof(typeReference)); } if (weavingContext is null) { throw new ArgumentNullException(nameof(weavingContext)); } var module = typeReference.Module; var observableCollectionTypes = new TypeDefinition[] { weavingContext.CortexNetTypesObservableDictionary.Resolve(), weavingContext.CortexNetTypesObservableSet.Resolve(), weavingContext.CortexNetTypesObservableCollection.Resolve(), }; var typeToCheck = typeReference.Resolve(); var interfacesToCheck = typeToCheck.Interfaces.OrderBy(x => x.InterfaceType.FullName).ToList(); foreach (var interfaceImplementation in observableCollectionTypes.SelectMany(x => x.Interfaces).OrderBy(x => x.InterfaceType.FullName)) { foreach (var interfaceImplementationToCheck in interfacesToCheck) { var compare = string.Compare(interfaceImplementation.InterfaceType.FullName, interfaceImplementationToCheck.InterfaceType.FullName, StringComparison.InvariantCulture); if (compare == 0) { return(true); } else if (compare > 0) { break; } } } return(false); }
/// <summary> /// Executes the <see cref="ModuleWeaver"/>. /// </summary> public override void Execute() { WeavingContext weavingContext = null; try { weavingContext = this.ModuleDefinition.AssemblyReferences.Any(x => x.Name == "Cortex.Net.Blazor") ? new BlazorWeavingContext(this) : new WeavingContext(this); #pragma warning disable CA1031 // Do not catch general exception types } catch #pragma warning restore CA1031 // Do not catch general exception types { this.WriteWarning(Resources.CannotLoadTypes); return; } var reactiveObjectInterfaceWeaver = new ReactiveObjectInterfaceWeaver(this, weavingContext); var enumerableWeaver = new EnumerableInterfaceWeaver(this, reactiveObjectInterfaceWeaver, weavingContext); var actionWeaver = new ActionWeaver(this, reactiveObjectInterfaceWeaver, weavingContext); var observableWeaver = new ObservableWeaver(this, enumerableWeaver, reactiveObjectInterfaceWeaver, weavingContext); var computedWeaver = new ComputedWeaver(this, reactiveObjectInterfaceWeaver, weavingContext); actionWeaver.Execute(); observableWeaver.Execute(); computedWeaver.Execute(); if (this.ModuleDefinition.AssemblyReferences.Any(x => x.Name == "Cortex.Net.Blazor")) { var blazorObserverWeaver = new BlazorObserverWeaver(this, reactiveObjectInterfaceWeaver, (BlazorWeavingContext)weavingContext); blazorObserverWeaver.Execute(); } reactiveObjectInterfaceWeaver.Execute(); }
/// <summary> /// Initializes a new instance of the <see cref="ActionWeaver"/> class. /// </summary> /// <param name="parentWeaver">A reference to the Parent Cortex.Net weaver.</param> /// <param name="processorQueue">The queue to add ILProcessor actions to.</param> /// <param name="weavingContext">The resolved types necessary by this weaver.</param> /// <exception cref="ArgumentNullException">When any of the arguments is null.</exception> public ActionWeaver(ModuleWeaver parentWeaver, ISharedStateAssignmentILProcessorQueue processorQueue, WeavingContext weavingContext) { this.parentWeaver = parentWeaver ?? throw new ArgumentNullException(nameof(parentWeaver)); this.processorQueue = processorQueue ?? throw new ArgumentNullException(nameof(processorQueue)); this.weavingContext = weavingContext ?? throw new ArgumentNullException(nameof(weavingContext)); }
/// <summary> /// Initializes a new instance of the <see cref="ComputedWeaver"/> class. /// </summary> /// <param name="parentWeaver">A reference to the Parent Cortex.Net weaver.</param> /// <param name="processorQueue">The queue to add ILProcessor actions to.</param> /// <exception cref="ArgumentNullException">When any of the arguments is null.</exception> /// <param name="weavingContext">The resolved types necessary by this weaver.</param> public ComputedWeaver(ModuleWeaver parentWeaver, ISharedStateAssignmentILProcessorQueue processorQueue, WeavingContext weavingContext) : base(parentWeaver, processorQueue, weavingContext) { }
/// <summary> /// Creates a field. /// </summary> /// <param name="classType">The type reference of the class.</param> /// <param name="fieldType">The type reference of the Field.</param> /// <param name="name">The name of the field.</param> /// <param name="weavingContext">The weaving context.</param> /// <param name="fieldAttributes">The field Atrributes.</param> /// <returns>The Field definition. It has already been added to the class type.</returns> public static FieldDefinition CreateField(this TypeDefinition classType, TypeReference fieldType, string name, WeavingContext weavingContext, FieldAttributes fieldAttributes = FieldAttributes.Private) { if (classType is null) { throw new ArgumentNullException(nameof(classType)); } if (fieldType is null) { throw new ArgumentNullException(nameof(fieldType)); } if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } if (weavingContext is null) { throw new ArgumentNullException(nameof(weavingContext)); } var field = new FieldDefinition(name, fieldAttributes, fieldType); // Add compiler generated attribute. var ctor = weavingContext.SystemRuntimeCompilerServicesCompilerGeneratedAttribute.Resolve().Methods.Single(x => x.IsConstructor && !x.IsStatic); var ctorRef = classType.Module.ImportReference(ctor); var compilerGeneratedAttribute = new CustomAttribute(ctorRef, new byte[] { 01, 00, 00, 00 }); field.CustomAttributes.Add(compilerGeneratedAttribute); // Add Debugger broswable attribute. ctor = weavingContext.SystemDiagnosticsDebuggerBrowsableAttribute.Resolve().Methods.Single(x => x.IsConstructor && !x.IsStatic); ctorRef = classType.Module.ImportReference(ctor); var debuggerBrowsableAttribute = new CustomAttribute(ctorRef, new byte[] { 01, 00, 00, 00, 00, 00, 00, 00 }); field.CustomAttributes.Add(debuggerBrowsableAttribute); classType.Fields.Add(field); return(field); }
/// <summary> /// Creates a backing field for a property. /// </summary> /// <param name="classType">The type reference of the class.</param> /// <param name="fieldType">The type reference of the Field.</param> /// <param name="name">The name of the Property.</param> /// <param name="weavingContext">The weaving context.</param> /// <returns>The Field definition. It has already been added to the class type.</returns> public static FieldDefinition CreateBackingField(this TypeDefinition classType, TypeReference fieldType, string name, WeavingContext weavingContext) { return(CreateField(classType, fieldType, $"<{name}>k__BackingField", weavingContext)); }
/// <summary> /// Creates a default getter for a property. /// </summary> /// <param name="classType">The type reference of the class.</param> /// <param name="backingField">A reference to the backing field.</param> /// <param name="name">The name of the property.</param> /// <param name="weavingContext">The weaving context.</param> /// <param name="methodAttributes">The methodAttributes for this getter. Default value is MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName.</param> /// <param name="emitAction">Extra emit action after default setter.</param> /// <returns>A method definition. The method is already added to the <paramref name="classType"/>.</returns> public static MethodDefinition CreateDefaultSetter( this TypeDefinition classType, FieldDefinition backingField, string name, WeavingContext weavingContext, MethodAttributes methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName, Action <ILProcessor> emitAction = null) { if (classType is null) { throw new ArgumentNullException(nameof(classType)); } if (backingField is null) { throw new ArgumentNullException(nameof(backingField)); } if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } if (weavingContext is null) { throw new ArgumentNullException(nameof(weavingContext)); } var moduleDefinition = classType.Module; var voidType = moduleDefinition.TypeSystem.Void; var splittedName = name.Split('.'); if (splittedName.Length > 1) { name = string.Join(".", splittedName.Take(splittedName.Length - 1)); name += $".set_{splittedName.Last()}"; } var method = new MethodDefinition(name, methodAttributes, voidType); method.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, backingField.FieldType)); // Add compiler generated attribute. var ctor = weavingContext.SystemRuntimeCompilerServicesCompilerGeneratedAttribute.Resolve().Methods.Single(x => x.IsConstructor && !x.IsStatic); var ctorRef = classType.Module.ImportReference(ctor); var compilerGeneratedAttribute = new CustomAttribute(ctorRef, new byte[] { 01, 00, 00, 00 }); method.CustomAttributes.Add(compilerGeneratedAttribute); // add method to class type. classType.Methods.Add(method); var backingFieldReference = moduleDefinition.ImportReference(backingField); // generate method body. var processor = method.Body.GetILProcessor(); processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Ldarg_1); processor.Emit(OpCodes.Stfld, backingFieldReference); // execute processor action before return. emitAction?.Invoke(processor); processor.Emit(OpCodes.Ret); return(method); }
/// <summary> /// Initializes a new instance of the <see cref="ReactiveObjectInterfaceWeaver"/> class. /// </summary> /// <param name="parentWeaver">The parent weaver.</param> /// <param name="weavingContext">The resolved types necessary by this weaver.</param> public ReactiveObjectInterfaceWeaver(ModuleWeaver parentWeaver, WeavingContext weavingContext) { this.parentWeaver = parentWeaver ?? throw new ArgumentNullException(nameof(parentWeaver)); this.weavingContext = weavingContext ?? throw new ArgumentNullException(nameof(weavingContext)); }
/// <summary> /// Gets the Action type for the private field that is added to the class for the private method. /// </summary> /// <param name="methodDefinition">The method definition for the action.</param> /// <param name="weavingContext">The weaving context.</param> /// <returns>A type reference.</returns> public static TypeReference GetActionType(this MethodDefinition methodDefinition, WeavingContext weavingContext) { if (methodDefinition is null) { throw new ArgumentNullException(nameof(methodDefinition)); } if (weavingContext is null) { throw new ArgumentNullException(nameof(weavingContext)); } var moduleDefinition = methodDefinition.Module; if (methodDefinition.Parameters == null || !methodDefinition.Parameters.Any()) { return(moduleDefinition.ImportReference(weavingContext.SystemAction[0])); } TypeReference genericActionType; switch (methodDefinition.Parameters.Count) { case int i when i > 0 && i <= 16: genericActionType = moduleDefinition.ImportReference(weavingContext.SystemAction[i]); break; default: throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.MoreThan16Parameters, methodDefinition.Name)); } var instance = new GenericInstanceType(genericActionType); foreach (var parameter in methodDefinition.Parameters) { instance.GenericArguments.Add(parameter.ParameterType); } return(instance); }
/// <summary> /// Initializes a new instance of the <see cref="ObservableWeaver"/> class. /// </summary> /// <param name="parentWeaver">A reference to the Parent Cortex.Net weaver.</param> /// <param name="enumerableInterfaceWeaver">An implementation of <see cref="IEnumerableInterfaceWeaver" />.</param> /// <param name="processorQueue">The queue to add ILProcessor actions to.</param> /// <param name="weavingContext">The resolved types necessary by this weaver.</param> /// <exception cref="ArgumentNullException">When any of the arguments is null.</exception> public ObservableWeaver(ModuleWeaver parentWeaver, IEnumerableInterfaceWeaver enumerableInterfaceWeaver, ISharedStateAssignmentILProcessorQueue processorQueue, WeavingContext weavingContext) : base(parentWeaver, processorQueue, weavingContext) { this.enumerableInterfaceWeaver = enumerableInterfaceWeaver ?? throw new ArgumentNullException(nameof(enumerableInterfaceWeaver)); }
/// <summary> /// Initializes a new instance of the <see cref="ObservableObjectWeaverBase"/> class. /// </summary> /// <param name="parentWeaver">The parent weaver.</param> /// <param name="processorQueue">The processor queue to add delegates to.</param> /// <param name="weavingContext">The resolved types necessary by this weaver.</param> protected ObservableObjectWeaverBase(ModuleWeaver parentWeaver, ISharedStateAssignmentILProcessorQueue processorQueue, WeavingContext weavingContext) { this.ParentWeaver = parentWeaver ?? throw new ArgumentNullException(nameof(parentWeaver)); this.ProcessorQueue = processorQueue ?? throw new ArgumentNullException(nameof(processorQueue)); this.WeavingContext = weavingContext ?? throw new ArgumentNullException(nameof(weavingContext)); }