internal static IGraphClient SharedWithAnnotations <TContext, TResolver, TConverter> (this IGraphClient graphClient, EntityService entityService, out TContext context, bool useConverter) where TContext : AnnotationsContext where TResolver : EntityResolver, new() where TConverter : EntityConverter, new() { if (graphClient == null) { throw new ArgumentNullException(nameof(graphClient)); } context = graphClient.GetAnnotationsContext() as TContext; if (context != null && (!useConverter ? context.EntityResolver?.GetType() == typeof(TResolver) : context.EntityConverter?.GetType() == typeof(TConverter)) && (entityService == null || context.EntityService.GetType() == entityService.GetType())) { //already attached return(graphClient); } TResolver resolver = null; TConverter converter = null; if (!useConverter) { resolver = new TResolver(); } else { converter = new TConverter(); } var resolverConverterObj = resolver ?? (object)converter; //find best constructor var parameters = new[] { graphClient, resolverConverterObj, entityService }.Where(p => p != null).ToArray(); var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var orderedConstructors = typeof(TContext).GetConstructors(flags) .OrderByDescending(c => c.GetParameters().Length) .Select(c => new { ctor = c, validParams = c.GetParameters().Select(p => parameters.FirstOrDefault (ip => p.ParameterType.IsAssignableFrom(ip.GetType()))) .ToArray() }) .OrderBy(nc => nc.validParams.Count(p => p == null)) .ToArray(); if (orderedConstructors?.Length > 0) { //find a constructor willing to create a valid instance with the available parameters foreach (var octor in orderedConstructors) { try { context = octor.ctor.Invoke(octor.validParams) as TContext; break; } catch { } } } if (context == null) { throw new InvalidOperationException(string.Format(Messages.NoValidConstructorError, typeof(TContext).Name)); } return(graphClient); }