diff options
author | Eric Maupin <ermaup@microsoft.com> | 2018-04-27 22:29:27 +0300 |
---|---|---|
committer | Eric Maupin <ermaup@microsoft.com> | 2018-05-01 00:54:20 +0300 |
commit | 6733b45455489e7f23988e2a1a58a36710a4b957 (patch) | |
tree | e1fb08be0baa3bd073c2677a2c78f78d9426fb38 /Xamarin.PropertyEditing | |
parent | e4e840486c5b1a05a125a09c94b6ed2a7c08a40a (diff) |
[Core] Make assignable types more reusable
Diffstat (limited to 'Xamarin.PropertyEditing')
4 files changed, 81 insertions, 29 deletions
diff --git a/Xamarin.PropertyEditing/AssignableTypesResult.cs b/Xamarin.PropertyEditing/AssignableTypesResult.cs index b16170a..94269ac 100644 --- a/Xamarin.PropertyEditing/AssignableTypesResult.cs +++ b/Xamarin.PropertyEditing/AssignableTypesResult.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Linq; +using Cadenza.Collections; namespace Xamarin.PropertyEditing { public class AssignableTypesResult { - public AssignableTypesResult (IReadOnlyList<ITypeInfo> assignableTypes) + public AssignableTypesResult (IReadOnlyCollection<ITypeInfo> assignableTypes) { if (assignableTypes == null) throw new ArgumentNullException (nameof(assignableTypes)); @@ -13,7 +15,7 @@ namespace Xamarin.PropertyEditing AssignableTypes = assignableTypes; } - public AssignableTypesResult (IReadOnlyList<ITypeInfo> suggestedTypes, IReadOnlyList<ITypeInfo> assignableTypes) + public AssignableTypesResult (IReadOnlyList<ITypeInfo> suggestedTypes, IReadOnlyCollection<ITypeInfo> assignableTypes) : this (assignableTypes) { if (suggestedTypes == null) @@ -27,9 +29,23 @@ namespace Xamarin.PropertyEditing get; } - public IReadOnlyList<ITypeInfo> AssignableTypes + public IReadOnlyCollection<ITypeInfo> AssignableTypes { get; } + + internal IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>> GetTypeTree () + { + var assemblies = new Dictionary<IAssemblyInfo, ILookup<string, ITypeInfo>> (); + foreach (ITypeInfo type in AssignableTypes) { + if (!assemblies.TryGetValue (type.Assembly, out ILookup<string, ITypeInfo> types)) { + assemblies[type.Assembly] = types = new ObservableLookup<string, ITypeInfo> (); + } + + ((IMutableLookup<string, ITypeInfo>) types).Add (type.NameSpace, type); + } + + return assemblies; + } } }
\ No newline at end of file diff --git a/Xamarin.PropertyEditing/Extensions.cs b/Xamarin.PropertyEditing/Extensions.cs index c6062c2..e789604 100644 --- a/Xamarin.PropertyEditing/Extensions.cs +++ b/Xamarin.PropertyEditing/Extensions.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace Xamarin.PropertyEditing { @@ -103,5 +104,37 @@ namespace Xamarin.PropertyEditing return self.IndexOf (value, comparison) >= 0; } + + public static async Task<AssignableTypesResult> GetCommonAssignableTypes (this IEnumerable<IObjectEditor> editors, IPropertyInfo property, bool childTypes) + { + if (editors == null) + throw new ArgumentNullException (nameof(editors)); + if (property == null) + throw new ArgumentNullException (nameof(property)); + + List<ITypeInfo> suggested = null; + HashSet<ITypeInfo> all = null; + var tasks = new HashSet<Task<AssignableTypesResult>> (editors.Select (oe => oe.GetAssignableTypesAsync (property, childTypes))); + + while (tasks.Count > 0) { + var task = await Task.WhenAny (tasks).ConfigureAwait (false); + tasks.Remove (task); + + if (suggested == null) { + suggested = new List<ITypeInfo> (task.Result.SuggestedTypes ?? Enumerable.Empty<ITypeInfo>()); + all = new HashSet<ITypeInfo> (task.Result.AssignableTypes); + continue; + } + + all.IntersectWith (task.Result.AssignableTypes); + + foreach (ITypeInfo type in suggested.ToArray()) { + if (!task.Result.AssignableTypes.Contains (type)) + suggested.Remove (type); + } + } + + return new AssignableTypesResult (suggested, all); + } } } diff --git a/Xamarin.PropertyEditing/Reflection/ReflectionObjectEditor.cs b/Xamarin.PropertyEditing/Reflection/ReflectionObjectEditor.cs index 19b8d7d..a851b2e 100644 --- a/Xamarin.PropertyEditing/Reflection/ReflectionObjectEditor.cs +++ b/Xamarin.PropertyEditing/Reflection/ReflectionObjectEditor.cs @@ -94,18 +94,7 @@ namespace Xamarin.PropertyEditing.Reflection public Task<AssignableTypesResult> GetAssignableTypesAsync (IPropertyInfo property, bool childTypes) { - return Task.Run (() => { - ReflectionPropertyInfo realInfo = (ReflectionPropertyInfo) property; - var assemblies = AppDomain.CurrentDomain.GetAssemblies (); - var entry = Assembly.GetEntryAssembly(); - - return new AssignableTypesResult (assemblies.Select (a => new { Assembly = a, Info = new AssemblyInfo (a.FullName, a == entry)}) - .SelectMany (a => - a.Assembly.DefinedTypes.Select (t => new { Type = t, Assembly = a })) - .AsParallel () - .Where (t => realInfo.Type.IsAssignableFrom (t.Type)) - .Select (t => new TypeInfo (t.Assembly.Info, t.Type.Namespace, t.Type.Name)).ToList()); - }); + return GetAssignableTypes (property, childTypes); } public async Task SetValueAsync<T> (IPropertyInfo property, ValueInfo<T> value, PropertyVariation variation = null) @@ -138,6 +127,31 @@ namespace Xamarin.PropertyEditing.Reflection }; } + internal static Task<AssignableTypesResult> GetAssignableTypes (IPropertyInfo property, bool childTypes) + { + return Task.Run (() => { + var types = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (a => a.GetTypes ()).AsParallel () + .Where (t => t.Namespace != null && !t.IsAbstract && !t.IsInterface && t.IsPublic && t.GetConstructor (Type.EmptyTypes) != null); + + Type type = property.Type; + if (childTypes) { + var generic = property.Type.GetInterface ("ICollection`1"); + if (generic != null) { + type = generic.GetGenericArguments()[0]; + } else { + type = typeof(object); + } + } + + types = types.Where (t => type.IsAssignableFrom (t)); + + return new AssignableTypesResult (types.Select (t => { + string asmName = t.Assembly.GetName ().Name; + return new TypeInfo (new AssemblyInfo (asmName, isRelevant: asmName.StartsWith ("Xamarin")), t.Namespace, t.Name); + }).ToList ()); + }); + } + private readonly object target; private readonly List<ReflectionPropertyInfo> properties = new List<ReflectionPropertyInfo> (); private readonly List<ReflectionEventInfo> events = new List<ReflectionEventInfo> (); diff --git a/Xamarin.PropertyEditing/ViewModels/ObjectPropertyViewModel.cs b/Xamarin.PropertyEditing/ViewModels/ObjectPropertyViewModel.cs index e491b23..af65bf8 100644 --- a/Xamarin.PropertyEditing/ViewModels/ObjectPropertyViewModel.cs +++ b/Xamarin.PropertyEditing/ViewModels/ObjectPropertyViewModel.cs @@ -233,19 +233,8 @@ namespace Xamarin.PropertyEditing.ViewModels private async Task<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> GetAssignableTypesAsync () { - Task<AssignableTypesResult>[] typeTasks = Editors.Select (o => o.GetAssignableTypesAsync (Property, childTypes: false)).ToArray(); - AssignableTypesResult[] lists = await Task.WhenAll (typeTasks).ConfigureAwait (false); - - var assemblies = new Dictionary<IAssemblyInfo, ILookup<string, ITypeInfo>> (); - foreach (ITypeInfo type in lists.SelectMany (t => t.AssignableTypes)) { - if (!assemblies.TryGetValue (type.Assembly, out ILookup<string, ITypeInfo> types)) { - assemblies[type.Assembly] = types = new ObservableLookup<string, ITypeInfo> (); - } - - ((IMutableLookup<string, ITypeInfo>) types).Add (type.NameSpace, type); - } - - return assemblies; + AssignableTypesResult result = await Editors.GetCommonAssignableTypes (Property, childTypes: false).ConfigureAwait (false); + return result.GetTypeTree (); } private async void CreateInstance () |