// Returns a new instance of a proxy the derives from 'baseType' and implements 'interfaceType' internal static object CreateProxyInstance( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type baseType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType) { Debug.Assert(baseType != null); Debug.Assert(interfaceType != null); GeneratedTypeInfo proxiedType = GetProxyType(baseType, interfaceType); return(Activator.CreateInstance(proxiedType.GeneratedType, new object[] { proxiedType.MethodInfos }) !); }
private static GeneratedTypeInfo GenerateProxyType( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type baseType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType) { // Parameter validation is deferred until the point we need to create the proxy. // This prevents unnecessary overhead revalidating cached proxy types. // The interface type must be an interface, not a class if (!interfaceType.IsInterface) { // "T" is the generic parameter seen via the public contract throw new ArgumentException(SR.Format(SR.InterfaceType_Must_Be_Interface, interfaceType.FullName), "T"); } // The base type cannot be sealed because the proxy needs to subclass it. if (baseType.IsSealed) { // "TProxy" is the generic parameter seen via the public contract throw new ArgumentException(SR.Format(SR.BaseType_Cannot_Be_Sealed, baseType.FullName), "TProxy"); } // The base type cannot be abstract if (baseType.IsAbstract) { throw new ArgumentException(SR.Format(SR.BaseType_Cannot_Be_Abstract, baseType.FullName), "TProxy"); } // The base type must have a public default ctor if (baseType.GetConstructor(Type.EmptyTypes) == null) { throw new ArgumentException(SR.Format(SR.BaseType_Must_Have_Default_Ctor, baseType.FullName), "TProxy"); } // Create a type that derives from 'baseType' provided by caller ProxyBuilder pb = s_proxyAssembly.CreateProxy("generatedProxy", baseType); foreach (Type t in interfaceType.GetInterfaces()) { pb.AddInterfaceImpl(t); } pb.AddInterfaceImpl(interfaceType); GeneratedTypeInfo generatedProxyType = pb.CreateType(); return(generatedProxyType); }
private void GenerateType(IndentedStringBuilder writer, INamedTypeSymbol ownerType) { if (_typeMap.ContainsKey(ownerType)) { return; } var ownerTypeName = GetGlobalQualifier(ownerType) + ownerType.ToString(); var flattenedProperties = from property in ownerType.GetAllProperties() where !property.IsStatic && !IsIgnoredType(property.ContainingSymbol as INamedTypeSymbol) && !IsNonBindable(property) && !IsOverride(property.GetMethod) select property; var properties = from property in ownerType.GetProperties() where !property.IsStatic && !IsNonBindable(property) && HasPublicGetter(property) && !IsOverride(property.GetMethod) select property; var propertyDependencyProperties = from property in ownerType.GetProperties() where property.IsStatic && Equals(property.Type, _dependencyPropertySymbol) select property.Name; var fieldDependencyProperties = from field in ownerType.GetFields() where field.IsStatic && Equals(field.Type, _dependencyPropertySymbol) select field.Name; var dependencyProperties = fieldDependencyProperties .Concat(propertyDependencyProperties) .ToArray(); properties = from prop in properties.Distinct(new PropertyNameEqualityComparer()) where !dependencyProperties.Contains(prop.Name + "Property") select prop; properties = properties .ToArray(); var typeInfo = new GeneratedTypeInfo( index: _typeMap.Count, hasProperties: properties.Any() || dependencyProperties.Any() ); _typeMap.Add(ownerType, typeInfo); var baseType = GetBaseType(ownerType); // Call the builders for the base types if (baseType != null) { GenerateType(writer, baseType); } writer.AppendLineInvariant("/// <summary>"); writer.AppendLineInvariant("/// Builder for {0}", ownerType.GetFullName()); writer.AppendLineInvariant("/// </summary>"); writer.AppendLineInvariant("[System.Runtime.CompilerServices.CompilerGeneratedAttribute]"); writer.AppendLineInvariant("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Maintainability\", \"CA1502:AvoidExcessiveComplexity\", Justification=\"Must be ignored even if generated code is checked.\")]"); writer.AppendLineInvariant("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Maintainability\", \"CA1506:AvoidExcessiveClassCoupling\", Justification = \"Must be ignored even if generated code is checked.\")]"); AnalyzerSuppressionsGenerator.Generate(writer, AnalyzerSuppressions); using (writer.BlockInvariant("static class MetadataBuilder_{0:000}", typeInfo.Index)) { var postWriter = new IndentedStringBuilder(); postWriter.Indent(writer.CurrentLevel); // Generate a parameter-less build to avoid generating a lambda during registration (avoids creating a caching backing field) writer.AppendLineInvariant("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Maintainability\", \"CA1502:AvoidExcessiveComplexity\", Justification=\"Must be ignored even if generated code is checked.\")]"); writer.AppendLineInvariant("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Maintainability\", \"CA1506:AvoidExcessiveClassCoupling\", Justification = \"Must be ignored even if generated code is checked.\")]"); writer.AppendLineInvariant("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Maintainability\", \"CA1505:AvoidUnmaintainableCode\", Justification = \"Must be ignored even if generated code is checked.\")]"); using (writer.BlockInvariant("internal static global::Uno.UI.DataBinding.IBindableType Build()")) { writer.AppendLineInvariant("return Build(null);"); } writer.AppendLineInvariant("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Maintainability\", \"CA1502:AvoidExcessiveComplexity\", Justification=\"Must be ignored even if generated code is checked.\")]"); writer.AppendLineInvariant("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Maintainability\", \"CA1506:AvoidExcessiveClassCoupling\", Justification = \"Must be ignored even if generated code is checked.\")]"); writer.AppendLineInvariant("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Maintainability\", \"CA1505:AvoidUnmaintainableCode\", Justification = \"Must be ignored even if generated code is checked.\")]"); using (writer.BlockInvariant("internal static global::Uno.UI.DataBinding.IBindableType Build(global::Uno.UI.DataBinding.BindableType parent)")) { writer.AppendLineInvariant( @"var bindableType = parent ?? new global::Uno.UI.DataBinding.BindableType({0}, typeof({1}));", flattenedProperties .Where(p => !IsStringIndexer(p) && HasPublicGetter(p)) .Count() , ExpandType(ownerType) ); // Call the builders for the base types if (baseType != null) { var baseTypeMapped = _typeMap.UnoGetValueOrDefault(baseType); writer.AppendLineInvariant(@"MetadataBuilder_{0:000}.Build(bindableType); // {1}", baseTypeMapped.Index, ExpandType(baseType)); } var ctor = ownerType.GetMethods().FirstOrDefault(m => m.MethodKind == MethodKind.Constructor && !m.Parameters.Any() && m.IsLocallyPublic(_currentModule)); if (ctor != null && IsCreateable(ownerType)) { using (writer.BlockInvariant("if(parent == null)")) { writer.AppendLineInvariant(@"bindableType.AddActivator(CreateInstance);"); postWriter.AppendLineInvariant($@"private static object CreateInstance() => new {ownerTypeName}();"); } } foreach (var property in properties) { var propertyTypeName = property.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); var propertyName = property.Name; if (IsStringIndexer(property)) { writer.AppendLineInvariant("bindableType.AddIndexer(GetIndexer, SetIndexer);"); postWriter.AppendLineInvariant($@"private static object GetIndexer(object instance, string name) => (({ownerTypeName})instance)[name];"); if (property.SetMethod != null) { postWriter.AppendLineInvariant($@"private static void SetIndexer(object instance, string name, object value) => (({ownerTypeName})instance)[name] = ({propertyTypeName})value;"); } else { postWriter.AppendLineInvariant("private static void SetIndexer(object instance, string name, object value) {{}}"); } continue; } if (property.IsIndexer) { // Other types of indexers are currently not supported. continue; } if ( property.SetMethod != null && property.SetMethod != null && property.SetMethod.IsLocallyPublic(_currentModule) ) { if (property.Type.IsValueType) { writer.AppendLineInvariant($@"bindableType.AddProperty(""{propertyName}"", typeof({propertyTypeName}), Get{propertyName}, Set{propertyName});"); postWriter.AppendLineInvariant($@"private static object Get{propertyName}(object instance, Windows.UI.Xaml.DependencyPropertyValuePrecedences? precedence) => (({ownerTypeName})instance).{propertyName};"); using (postWriter.BlockInvariant($@"private static void Set{propertyName}(object instance, object value, Windows.UI.Xaml.DependencyPropertyValuePrecedences? precedence)")) { using (postWriter.BlockInvariant($"if(value != null)")) { postWriter.AppendLineInvariant($"(({ownerTypeName})instance).{propertyName} = ({propertyTypeName})value;"); } } } else { writer.AppendLineInvariant($@"bindableType.AddProperty(""{propertyName}"", typeof({propertyTypeName}), Get{propertyName}, Set{propertyName});"); postWriter.AppendLineInvariant($@"private static object Get{propertyName}(object instance, Windows.UI.Xaml.DependencyPropertyValuePrecedences? precedence) => (({ownerTypeName})instance).{propertyName};"); postWriter.AppendLineInvariant($@"private static void Set{propertyName}(object instance, object value, Windows.UI.Xaml.DependencyPropertyValuePrecedences? precedence) => (({ownerTypeName})instance).{propertyName} = ({propertyTypeName})value;"); } } else if (HasPublicGetter(property)) { writer.AppendLineInvariant($@"bindableType.AddProperty(""{propertyName}"", typeof({propertyTypeName}), Get{propertyName});"); postWriter.AppendLineInvariant($@"private static object Get{propertyName}(object instance, Windows.UI.Xaml.DependencyPropertyValuePrecedences? precedence) => (({ownerTypeName})instance).{propertyName};"); } } foreach (var dependencyProperty in dependencyProperties) { var propertyName = dependencyProperty.TrimEnd("Property"); var getMethod = ownerType.GetMethods().FirstOrDefault(m => m.Name == "Get" + propertyName && m.Parameters.Length == 1 && m.IsLocallyPublic(_currentModule)); var setMethod = ownerType.GetMethods().FirstOrDefault(m => m.Name == "Set" + propertyName && m.Parameters.Length == 2 && m.IsLocallyPublic(_currentModule)); if (getMethod == null) { getMethod = ownerType .GetProperties() .FirstOrDefault(p => p.Name == propertyName && (p.GetMethod?.IsLocallyPublic(_currentModule) ?? false)) ?.GetMethod; } if (getMethod != null) { var getter = $"{XamlConstants.Types.DependencyObjectExtensions}.GetValue(instance, {ownerTypeName}.{propertyName}Property, precedence)"; var setter = $"{XamlConstants.Types.DependencyObjectExtensions}.SetValue(instance, {ownerTypeName}.{propertyName}Property, value, precedence)"; var propertyType = GetGlobalQualifier(getMethod.ReturnType) + SanitizeTypeName(getMethod.ReturnType.ToString()); writer.AppendLineInvariant($@"bindableType.AddProperty(""{propertyName}"", typeof({propertyType}), Get{propertyName}, Set{propertyName});"); postWriter.AppendLineInvariant($@"private static object Get{propertyName}(object instance, Windows.UI.Xaml.DependencyPropertyValuePrecedences? precedence) => {getter};"); postWriter.AppendLineInvariant($@"private static void Set{propertyName}(object instance, object value, Windows.UI.Xaml.DependencyPropertyValuePrecedences? precedence) => {setter};"); } } writer.AppendLineInvariant(@"return bindableType;"); } writer.Append(postWriter.ToString()); } writer.AppendLine(); }