From 8394185a621c8daceeefa6d0fac9c52360c9b216 Mon Sep 17 00:00:00 2001 From: Blake Niemyjski Date: Fri, 3 Jun 2016 12:07:27 -0500 Subject: [PATCH 1/3] Added support for NETSTANDARD 1.0+ and PCL Profile 151 --- src/TinyIoC/TinyIoC.cs | 325 ++++++++++++++++++++++++++++------------- 1 file changed, 223 insertions(+), 102 deletions(-) diff --git a/src/TinyIoC/TinyIoC.cs b/src/TinyIoC/TinyIoC.cs index d3154bb..c346163 100644 --- a/src/TinyIoC/TinyIoC.cs +++ b/src/TinyIoC/TinyIoC.cs @@ -42,6 +42,20 @@ #undef APPDOMAIN_GETASSEMBLIES #undef COMPILED_EXPRESSIONS #undef READER_WRITER_LOCK_SLIM +#undef SERIALIZABLE +#endif + +#if NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 +#undef COMPILED_EXPRESSIONS +#undef READER_WRITER_LOCK_SLIM +#endif + +#if NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 +#undef APPDOMAIN_GETASSEMBLIES +#endif + +#if NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 || NETSTANDARD1_5 || NETSTANDARD1_6 +#undef SERIALIZABLE #endif // CompactFramework / Windows Phone 7 @@ -75,12 +89,6 @@ #define USE_OBJECT_CONSTRUCTOR #endif - -#if NETSTANDARD1_5 -#undef SERIALIZABLE -#undef APPDOMAIN_GETASSEMBLIES -#endif - #endregion #if SERIALIZABLE using System.Runtime.Serialization; @@ -327,8 +335,12 @@ public static Type[] SafeGetTypes(this Assembly assembly) try { +#if PORTABLE || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 + assemblies = assembly.ExportedTypes.ToArray(); +#else assemblies = assembly.GetTypes(); - } +#endif + } catch (System.IO.FileNotFoundException) { assemblies = new Type[] { }; @@ -347,6 +359,32 @@ public static Type[] SafeGetTypes(this Assembly assembly) } } +#if PORTABLE || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 + [Flags] + internal enum BindingFlags { + Default = 0, + IgnoreCase = 1, + DeclaredOnly = 2, + Instance = 4, + Static = 8, + Public = 16, + NonPublic = 32, + FlattenHierarchy = 64, + InvokeMethod = 256, + CreateInstance = 512, + GetField = 1024, + SetField = 2048, + GetProperty = 4096, + SetProperty = 8192, + PutDispProperty = 16384, + ExactBinding = 65536, + PutRefDispProperty = 32768, + SuppressChangeType = 131072, + OptionalParamBinding = 262144, + IgnoreReturn = 16777216 + } +#endif + #if TINYIOC_INTERNAL internal #else @@ -361,34 +399,139 @@ static TypeExtensions() _genericMethodCache = new SafeDictionary(); } - //#if NETFX_CORE - // /// - // /// Gets a generic method from a type given the method name, generic types and parameter types - // /// - // /// Source type - // /// Name of the method - // /// Generic types to use to make the method generic - // /// Method parameters - // /// MethodInfo or null if no matches found - // /// - // /// - // public static MethodInfo GetGenericMethod(this Type sourceType, string methodName, Type[] genericTypes, Type[] parameterTypes) - // { - // MethodInfo method; - // var cacheKey = new GenericMethodCacheKey(sourceType, methodName, genericTypes, parameterTypes); - - // // Shouldn't need any additional locking - // // we don't care if we do the method info generation - // // more than once before it gets cached. - // if (!_genericMethodCache.TryGetValue(cacheKey, out method)) - // { - // method = GetMethod(sourceType, methodName, genericTypes, parameterTypes); - // _genericMethodCache[cacheKey] = method; - // } - - // return method; - // } - //#else +#if PORTABLE || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 + private static BindingFlags DefaultFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; + + public static ConstructorInfo[] GetConstructors(this Type type) + { + return type.GetConstructors(DefaultFlags); + } + + public static ConstructorInfo[] GetConstructors(this Type type, BindingFlags bindingFlags) + { + return type.GetConstructors(bindingFlags, null); + } + + private static ConstructorInfo[] GetConstructors(this Type type, BindingFlags bindingFlags, IList parameterTypes) + { + return type.GetTypeInfo().DeclaredConstructors.Where( + c => + { + if (!TestAccessibility(c, bindingFlags)) + { + return false; + } + + if (parameterTypes != null && !c.GetParameters().Select(p => p.ParameterType).SequenceEqual(parameterTypes)) + { + return false; + } + + return true; + }).ToArray(); + } + + public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo) { + return propertyInfo.GetGetMethod(false); + } + + public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo, bool nonPublic) { + MethodInfo getMethod = propertyInfo.GetMethod; + if (getMethod != null && (getMethod.IsPublic || nonPublic)) { + return getMethod; + } + + return null; + } + + public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo) { + return propertyInfo.GetSetMethod(false); + } + + public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo, bool nonPublic) { + MethodInfo setMethod = propertyInfo.SetMethod; + if (setMethod != null && (setMethod.IsPublic || nonPublic)) { + return setMethod; + } + + return null; + } + + public static Type[] GetGenericArguments(this Type type) + { + return type.GetTypeInfo().GenericTypeArguments; + } + + public static IEnumerable GetProperties(this Type type) + { + TypeInfo t = type.GetTypeInfo(); + IList properties = new List(); + while (t != null) + { + foreach (PropertyInfo member in t.DeclaredProperties) + { + if (!properties.Any(p => p.Name == member.Name)) + { + properties.Add(member); + } + } + t = (t.BaseType != null) ? t.BaseType.GetTypeInfo() : null; + } + + return properties; + } + + public static IEnumerable GetInterfaces(this Type type) + { + return type.GetTypeInfo().ImplementedInterfaces; + } + + public static MethodInfo GetMethod(this Type type, string name, IList parameterTypes) + { + return type.GetMethod(name, DefaultFlags, null, parameterTypes, null); + } + + public static MethodInfo GetMethod(this Type type, string name, BindingFlags bindingFlags, object placeHolder1, IList parameterTypes, object placeHolder2) + { + return type.GetTypeInfo().DeclaredMethods.Where( + m => + { + if (name != null && m.Name != name) + { + return false; + } + + if (!TestAccessibility(m, bindingFlags)) + { + return false; + } + + return m.GetParameters().Select(p => p.ParameterType).SequenceEqual(parameterTypes); + }).SingleOrDefault(); + } + + public static IEnumerable GetMethods(this Type type, BindingFlags bindingFlags) + { + return type.GetTypeInfo().DeclaredMethods; + } + + public static bool IsAssignableFrom(this Type type, Type c) + { + return type.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo()); + } + + private static bool TestAccessibility(MethodBase member, BindingFlags bindingFlags) + { + bool visibility = (member.IsPublic && bindingFlags.HasFlag(BindingFlags.Public)) || + (!member.IsPublic && bindingFlags.HasFlag(BindingFlags.NonPublic)); + + bool instance = (member.IsStatic && bindingFlags.HasFlag(BindingFlags.Static)) || + (!member.IsStatic && bindingFlags.HasFlag(BindingFlags.Instance)); + + return visibility && instance; + } +#endif + /// /// Gets a generic method from a type given the method name, binding flags, generic types and parameter types /// @@ -564,9 +707,9 @@ internal static void ForEach(this List list, Action callback) } #endif - #endregion +#endregion - #region TinyIoC Exception Types +#region TinyIoC Exception Types #if SERIALIZABLE [Serializable] #endif @@ -764,9 +907,9 @@ private static string GetTypesString(IEnumerable types) return string.Join(",", typeNames.ToArray()); } } - #endregion +#endregion - #region Public Setup / Settings Classes +#region Public Setup / Settings Classes /// /// Name/Value pairs for specifying "user" parameters when resolving /// @@ -926,7 +1069,7 @@ public static ResolveOptions FailUnregisteredOnly } } } - #endregion +#endregion #if TINYIOC_INTERNAL internal @@ -935,7 +1078,7 @@ public static ResolveOptions FailUnregisteredOnly #endif sealed partial class TinyIoCContainer : IDisposable { - #region Fake NETFX_CORE Classes +#region Fake NETFX_CORE Classes #if NETFX_CORE private sealed class MethodAccessException : Exception { @@ -980,9 +1123,9 @@ public async Task> GetAssembliesAsync() } } #endif - #endregion +#endregion - #region "Fluent" API +#region "Fluent" API /// /// Registration options for "fluent" API /// @@ -1001,7 +1144,7 @@ public RegisterOptions(TinyIoCContainer container, TypeRegistration registration /// Make registration a singleton (single instance) if possible /// /// RegisterOptions - /// + /// public RegisterOptions AsSingleton() { var currentFactory = _Container.GetCurrentFactory(_Registration); @@ -1016,7 +1159,7 @@ public RegisterOptions AsSingleton() /// Make registration multi-instance if possible /// /// RegisterOptions - /// + /// public RegisterOptions AsMultiInstance() { var currentFactory = _Container.GetCurrentFactory(_Registration); @@ -1031,7 +1174,7 @@ public RegisterOptions AsMultiInstance() /// Make registration hold a weak reference if possible /// /// RegisterOptions - /// + /// public RegisterOptions WithWeakReference() { var currentFactory = _Container.GetCurrentFactory(_Registration); @@ -1046,7 +1189,7 @@ public RegisterOptions WithWeakReference() /// Make registration hold a strong reference if possible /// /// RegisterOptions - /// + /// public RegisterOptions WithStrongReference() { var currentFactory = _Container.GetCurrentFactory(_Registration); @@ -1130,7 +1273,7 @@ public MultiRegisterOptions(IEnumerable registerOptions) /// Make registration a singleton (single instance) if possible /// /// RegisterOptions - /// + /// public MultiRegisterOptions AsSingleton() { _RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsSingleton()); @@ -1141,7 +1284,7 @@ public MultiRegisterOptions AsSingleton() /// Make registration multi-instance if possible /// /// MultiRegisterOptions - /// + /// public MultiRegisterOptions AsMultiInstance() { _RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsMultiInstance()); @@ -1188,17 +1331,17 @@ private IEnumerable ExecuteOnAllRegisterOptions(Func /// Attempt to automatically register all non-generic classes and interfaces in the current app domain. /// @@ -1430,7 +1573,7 @@ public RegisterOptions Register(Type registerType, Func /// Creates/replaces a container class registration with default options. /// - /// Type to register + /// Type to register /// RegisterOptions for fluent API public RegisterOptions Register() where RegisterType : class @@ -1441,7 +1584,7 @@ public RegisterOptions Register() /// /// Creates/replaces a named container class registration with default options. /// - /// Type to register + /// Type to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(string name) @@ -1622,9 +1765,9 @@ where j.Count() > 1 return new MultiRegisterOptions(registerOptions); } - #endregion +#endregion - #region Unregistration +#region Unregistration /// /// Remove a container class registration. @@ -1670,9 +1813,9 @@ public bool Unregister(Type registerType, string name) return RemoveRegistration(typeRegistration); } - #endregion +#endregion - #region Resolution +#region Resolution /// /// Attempts to resolve a type using default options. /// @@ -2578,10 +2721,10 @@ public void BuildUp(object input, ResolveOptions resolveOptions) { BuildUpInternal(input, resolveOptions); } - #endregion - #endregion +#endregion +#endregion - #region Object Factories +#region Object Factories /// /// Provides custom lifetime management for ASP.Net per-request lifetimes etc. /// @@ -3187,9 +3330,9 @@ public void Dispose() _LifetimeProvider.ReleaseObject(); } } - #endregion +#endregion - #region Singleton Container +#region Singleton Container private static readonly TinyIoCContainer _Current = new TinyIoCContainer(); static TinyIoCContainer() @@ -3206,9 +3349,9 @@ public static TinyIoCContainer Current return _Current; } } - #endregion +#endregion - #region Type Registrations +#region Type Registrations public sealed class TypeRegistration { private int _hashCode; @@ -3255,9 +3398,9 @@ public override int GetHashCode() private delegate object ObjectConstructor(params object[] parameters); private static readonly SafeDictionary _ObjectConstructorCache = new SafeDictionary(); #endif - #endregion +#endregion - #region Constructors +#region Constructors public TinyIoCContainer() { _RegisteredTypes = new SafeDictionary(); @@ -3271,9 +3414,9 @@ private TinyIoCContainer(TinyIoCContainer parent) { _Parent = parent; } - #endregion +#endregion - #region Internal Methods +#region Internal Methods private readonly object _AutoRegisterLock = new object(); private void AutoRegisterInternal(IEnumerable assemblies, DuplicateImplementationActions duplicateAction, Func registrationPredicate) { @@ -3291,7 +3434,7 @@ private void AutoRegisterInternal(IEnumerable assemblies, DuplicateImp { RegisterInternal(type, string.Empty, GetDefaultObjectFactory(type, type)); } -#if PORTABLE +#if PORTABLE || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 || NETSTANDARD1_5 || NETSTANDARD1_6 catch (MemberAccessException) #else catch (MethodAccessException) @@ -3330,7 +3473,7 @@ where localType.IsAssignableFrom(implementationType) { RegisterInternal(type, string.Empty, GetDefaultObjectFactory(type, firstImplementation)); } -#if PORTABLE +#if PORTABLE || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 || NETSTANDARD1_5 || NETSTANDARD1_6 catch (MemberAccessException) #else catch (MethodAccessException) @@ -4003,28 +4146,6 @@ private IEnumerable ResolveAllInternal(Type resolveType, bool includeUnn private static bool IsValidAssignment(Type registerType, Type registerImplementation) { - //#if NETFX_CORE - // var registerTypeDef = registerType.GetTypeInfo(); - // var registerImplementationDef = registerImplementation.GetTypeInfo(); - - // if (!registerTypeDef.IsGenericTypeDefinition) - // { - // if (!registerTypeDef.IsAssignableFrom(registerImplementationDef)) - // return false; - // } - // else - // { - // if (registerTypeDef.IsInterface()) - // { - // if (!registerImplementationDef.ImplementedInterfaces.Any(t => t.GetTypeInfo().Name == registerTypeDef.Name)) - // return false; - // } - // else if (registerTypeDef.IsAbstract() && registerImplementationDef.BaseType() != registerType) - // { - // return false; - // } - // } - //#else if (!registerType.IsGenericTypeDefinition()) { if (!registerType.IsAssignableFrom(registerImplementation)) @@ -4034,7 +4155,7 @@ private static bool IsValidAssignment(Type registerType, Type registerImplementa { if (registerType.IsInterface()) { -#if (PORTABLE || NETSTANDARD1_5) +#if (PORTABLE || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 || NETSTANDARD1_5 || NETSTANDARD1_6) if (!registerImplementation.GetInterfaces().Any(t => t.Name == registerType.Name)) return false; #else @@ -4051,9 +4172,9 @@ private static bool IsValidAssignment(Type registerType, Type registerImplementa return true; } - #endregion +#endregion - #region IDisposable Members +#region IDisposable Members bool disposed = false; public void Dispose() { @@ -4067,10 +4188,10 @@ public void Dispose() } } - #endregion +#endregion } -#if NETSTANDARD1_5 +#if PORTABLE || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 || NETSTANDARD1_5 || NETSTANDARD1_6 static class ReverseTypeExtender { public static bool IsClass(this Type type) @@ -4125,7 +4246,7 @@ public static Assembly Assembly(this Type type) } #endif // reverse shim for WinRT SR changes... -#if (!NETFX_CORE && !NETSTANDARD1_5) +#if (!NETFX_CORE && !PORTABLE && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NETSTANDARD1_3 && !NETSTANDARD1_4 && !NETSTANDARD1_5 || NETSTANDARD1_6) static class ReverseTypeExtender { public static bool IsClass(this Type type) @@ -4179,4 +4300,4 @@ public static Assembly Assembly(this Type type) } } #endif -} +} \ No newline at end of file From 25edef91c337848106c3438a99a6847f353f77e2 Mon Sep 17 00:00:00 2001 From: Blake Niemyjski Date: Mon, 6 Jun 2016 08:51:06 -0500 Subject: [PATCH 2/3] Update TinyIoC.cs --- src/TinyIoC/TinyIoC.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TinyIoC/TinyIoC.cs b/src/TinyIoC/TinyIoC.cs index c346163..1457e19 100644 --- a/src/TinyIoC/TinyIoC.cs +++ b/src/TinyIoC/TinyIoC.cs @@ -4246,7 +4246,7 @@ public static Assembly Assembly(this Type type) } #endif // reverse shim for WinRT SR changes... -#if (!NETFX_CORE && !PORTABLE && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NETSTANDARD1_3 && !NETSTANDARD1_4 && !NETSTANDARD1_5 || NETSTANDARD1_6) +#if (!NETFX_CORE && !PORTABLE && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NETSTANDARD1_3 && !NETSTANDARD1_4 && !NETSTANDARD1_5 || !NETSTANDARD1_6) static class ReverseTypeExtender { public static bool IsClass(this Type type) @@ -4300,4 +4300,4 @@ public static Assembly Assembly(this Type type) } } #endif -} \ No newline at end of file +} From 6ce8043fdedb9565875391f9fa39742a5578ccd3 Mon Sep 17 00:00:00 2001 From: Blake Niemyjski Date: Thu, 23 Jun 2016 14:21:32 -0500 Subject: [PATCH 3/3] Update TinyIoC.cs --- src/TinyIoC/TinyIoC.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TinyIoC/TinyIoC.cs b/src/TinyIoC/TinyIoC.cs index 1457e19..388b2e3 100644 --- a/src/TinyIoC/TinyIoC.cs +++ b/src/TinyIoC/TinyIoC.cs @@ -50,7 +50,7 @@ #undef READER_WRITER_LOCK_SLIM #endif -#if NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 +#if NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 #undef APPDOMAIN_GETASSEMBLIES #endif