From d534471515eafa42122d445d1cfcdf20c3442779 Mon Sep 17 00:00:00 2001 From: dougbu Date: Mon, 17 Mar 2014 21:02:25 -0700 Subject: [PATCH] Merge two `TypeExtensions` classes into Common\TypeExtensions.cs - add missing `[NotNull]` attributes - remove now-unneeded usings for ...ModelBinding.Internal namespace - remove TypeExtensionTests.cs; don't add .NET 4.5-only `[InternalsVisibleTo]` for low-level `IsCompatibleWith()` extension --- src/Common/TypeExtensions.cs | 136 ++++++++++++++++++ src/Common/project.json | 2 + .../Extensions/TypeExtensions.cs | 91 ------------ .../Binders/ComplexModelDtoResult.cs | 3 +- .../Internal/TypeExtensions.cs | 53 ------- .../project.json | 1 + .../project.json | 1 + src/Microsoft.AspNet.Mvc/project.json | 2 + .../Internal/TypeExtensionTests.cs | 66 --------- 9 files changed, 143 insertions(+), 212 deletions(-) create mode 100644 src/Common/TypeExtensions.cs delete mode 100644 src/Microsoft.AspNet.Mvc.Core/Extensions/TypeExtensions.cs delete mode 100644 src/Microsoft.AspNet.Mvc.ModelBinding/Internal/TypeExtensions.cs delete mode 100644 test/Microsoft.AspNet.Mvc.ModelBinding.Test/Internal/TypeExtensionTests.cs diff --git a/src/Common/TypeExtensions.cs b/src/Common/TypeExtensions.cs new file mode 100644 index 0000000000..027b4a75b4 --- /dev/null +++ b/src/Common/TypeExtensions.cs @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Reflection; + +namespace Microsoft.AspNet.Mvc +{ + internal static class TypeExtensions + { +#if NETFX_CORE || K10 + private static bool EqualTo([NotNull] this Type[] t1, [NotNull] Type[] t2) + { + if (t1.Length != t2.Length) + { + return false; + } + + for (int idx = 0; idx < t1.Length; ++idx) + { + if (t1[idx] != t2[idx]) + { + return false; + } + } + + return true; + } + + public static ConstructorInfo GetConstructor([NotNull] this Type type, Type[] types) + { + return type.GetTypeInfo().DeclaredConstructors + .Where(c => c.IsPublic) + .SingleOrDefault(c => c.GetParameters() + .Select(p => p.ParameterType).ToArray().EqualTo(types)); + } +#endif + + public static Type ExtractGenericInterface([NotNull] this Type queryType, Type interfaceType) + { + Func matchesInterface = t => t.IsGenericType() && t.GetGenericTypeDefinition() == interfaceType; + return (matchesInterface(queryType)) ? queryType : queryType.GetInterfaces().FirstOrDefault(matchesInterface); + } + +#if NETFX_CORE || K10 + public static Type[] GetGenericArguments([NotNull] this Type type) + { + return type.GetTypeInfo().GenericTypeArguments; + } + + public static Type[] GetInterfaces([NotNull] this Type type) + { + return type.GetTypeInfo().ImplementedInterfaces.ToArray(); + } +#endif + +#if NETFX_CORE || K10 + public static bool IsAssignableFrom([NotNull] this Type type, [NotNull] Type c) + { + return type.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo()); + } +#endif + + public static bool IsGenericType([NotNull] this Type type) + { +#if NETFX_CORE || K10 + return type.GetTypeInfo().IsGenericType; +#else + return type.IsGenericType; +#endif + } + + public static bool IsInterface([NotNull] this Type type) + { +#if NETFX_CORE || K10 + return type.GetTypeInfo().IsInterface; +#else + return type.IsInterface; +#endif + } + + public static bool IsValueType([NotNull] this Type type) + { +#if NETFX_CORE || K10 + return type.GetTypeInfo().IsValueType; +#else + return type.IsValueType; +#endif + } + + public static bool IsCompatibleWith([NotNull] this Type type, object value) + { + return (value == null && AllowsNullValue(type)) || + (value != null && type.GetTypeInfo().IsAssignableFrom(value.GetType().GetTypeInfo())); + } + + public static bool IsNullableValueType([NotNull] this Type type) + { + return Nullable.GetUnderlyingType(type) != null; + } + + public static bool AllowsNullValue([NotNull] this Type type) + { + return (!type.GetTypeInfo().IsValueType || IsNullableValueType(type)); + } + + public static bool HasStringConverter([NotNull] this Type type) + { + // TODO: This depends on TypeConverter which does not exist in the CoreCLR. + // return TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string)); + TypeInfo typeInfo = type.GetTypeInfo(); + if (typeInfo.IsPrimitive || type == typeof(string)) + { + return true; + } + if (IsNullableValueType(type) && HasStringConverter(type.GenericTypeArguments[0])) + { + // Nullable where T is a primitive type or has a type converter + return true; + } + return false; + } + + public static Type[] GetTypeArgumentsIfMatch([NotNull] Type closedType, Type matchingOpenType) + { + TypeInfo closedTypeInfo = closedType.GetTypeInfo(); + if (!closedTypeInfo.IsGenericType) + { + return null; + } + + Type openType = closedType.GetGenericTypeDefinition(); + return (matchingOpenType == openType) ? closedTypeInfo.GenericTypeArguments : null; + } + } +} diff --git a/src/Common/project.json b/src/Common/project.json index dfe6f04751..8a27758e16 100644 --- a/src/Common/project.json +++ b/src/Common/project.json @@ -1,6 +1,8 @@ { "shared": "*.cs", "dependencies": { + "System.Linq": "4.0.0.0", + "System.Reflection": "4.0.10.0", "System.Runtime" : "4.0.20.0" } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/Extensions/TypeExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/Extensions/TypeExtensions.cs deleted file mode 100644 index 09e4c830ae..0000000000 --- a/src/Microsoft.AspNet.Mvc.Core/Extensions/TypeExtensions.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Reflection; - -namespace Microsoft.AspNet.Mvc -{ - internal static class TypeExtensions - { -#if NETFX_CORE || K10 - private static bool EqualTo(this Type[] t1, Type[] t2) - { - if (t1.Length != t2.Length) - { - return false; - } - - for (int idx = 0; idx < t1.Length; ++idx) - { - if (t1[idx] != t2[idx]) - { - return false; - } - } - - return true; - } - - public static ConstructorInfo GetConstructor(this Type type, Type[] types) - { - return type.GetTypeInfo().DeclaredConstructors - .Where(c => c.IsPublic) - .SingleOrDefault(c => c.GetParameters() - .Select(p => p.ParameterType).ToArray().EqualTo(types)); - } -#endif - - public static Type ExtractGenericInterface(this Type queryType, Type interfaceType) - { - Func matchesInterface = t => t.IsGenericType() && t.GetGenericTypeDefinition() == interfaceType; - return (matchesInterface(queryType)) ? queryType : queryType.GetInterfaces().FirstOrDefault(matchesInterface); - } - -#if NETFX_CORE || K10 - public static Type[] GetGenericArguments(this Type type) - { - return type.GetTypeInfo().GenericTypeArguments; - } - - public static Type[] GetInterfaces(this Type type) - { - return type.GetTypeInfo().ImplementedInterfaces.ToArray(); - } -#endif - -#if NETFX_CORE || K10 - public static bool IsAssignableFrom(this Type type, Type c) - { - return type.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo()); - } -#endif - - public static bool IsGenericType(this Type type) - { -#if NETFX_CORE || K10 - return type.GetTypeInfo().IsGenericType; -#else - return type.IsGenericType; -#endif - } - - public static bool IsInterface(this Type type) - { -#if NETFX_CORE || K10 - return type.GetTypeInfo().IsInterface; -#else - return type.IsInterface; -#endif - } - - public static bool IsValueType(this Type type) - { -#if NETFX_CORE || K10 - return type.GetTypeInfo().IsValueType; -#else - return type.IsValueType; -#endif - } - } -} diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ComplexModelDtoResult.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ComplexModelDtoResult.cs index 76d1c83542..f3c4d5a10d 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ComplexModelDtoResult.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ComplexModelDtoResult.cs @@ -1,5 +1,4 @@ -using Microsoft.AspNet.Mvc.ModelBinding.Internal; - + namespace Microsoft.AspNet.Mvc.ModelBinding { public sealed class ComplexModelDtoResult diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Internal/TypeExtensions.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Internal/TypeExtensions.cs deleted file mode 100644 index 117d413f0f..0000000000 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Internal/TypeExtensions.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Reflection; - -namespace Microsoft.AspNet.Mvc.ModelBinding.Internal -{ - public static class TypeExtensions - { - public static bool IsCompatibleWith([NotNull] this Type type, object value) - { - return (value == null && AllowsNullValue(type)) || - (value != null && type.GetTypeInfo().IsAssignableFrom(value.GetType().GetTypeInfo())); - } - - public static bool IsNullableValueType([NotNull] this Type type) - { - return Nullable.GetUnderlyingType(type) != null; - } - - public static bool AllowsNullValue([NotNull] this Type type) - { - return (!type.GetTypeInfo().IsValueType || IsNullableValueType(type)); - } - - public static bool HasStringConverter([NotNull] this Type type) - { - // TODO: This depends on TypeConverter which does not exist in the CoreCLR. - // return TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string)); - TypeInfo typeInfo = type.GetTypeInfo(); - if (typeInfo.IsPrimitive || type == typeof(string)) - { - return true; - } - if (IsNullableValueType(type) && HasStringConverter(type.GenericTypeArguments[0])) - { - // Nullable where T is a primitive type or has a type converter - return true; - } - return false; - } - - public static Type[] GetTypeArgumentsIfMatch([NotNull] Type closedType, Type matchingOpenType) - { - TypeInfo closedTypeInfo = closedType.GetTypeInfo(); - if (!closedTypeInfo.IsGenericType) - { - return null; - } - - Type openType = closedType.GetGenericTypeDefinition(); - return (matchingOpenType == openType) ? closedTypeInfo.GenericTypeArguments : null; - } - } -} diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/project.json b/src/Microsoft.AspNet.Mvc.Razor.Host/project.json index 21a4d638d1..b881507539 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/project.json +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/project.json @@ -11,6 +11,7 @@ "System.Diagnostics.Debug": "4.0.10.0", "System.Globalization": "4.0.10.0", "System.IO": "4.0.0.0", + "System.Linq": "4.0.0.0", "System.Reflection": "4.0.10.0", "System.Resources.ResourceManager": "4.0.0.0", "System.Runtime": "4.0.20.0", diff --git a/src/Microsoft.AspNet.Mvc.Rendering/project.json b/src/Microsoft.AspNet.Mvc.Rendering/project.json index 9d996b058f..410d5cc4e4 100644 --- a/src/Microsoft.AspNet.Mvc.Rendering/project.json +++ b/src/Microsoft.AspNet.Mvc.Rendering/project.json @@ -18,6 +18,7 @@ "System.Dynamic.Runtime": "4.0.0.0", "System.Globalization": "4.0.10.0", "System.IO": "4.0.0.0", + "System.Linq": "4.0.0.0", "System.Reflection": "4.0.10.0", "System.Reflection.Extensions": "4.0.0.0", "System.Resources.ResourceManager": "4.0.0.0", diff --git a/src/Microsoft.AspNet.Mvc/project.json b/src/Microsoft.AspNet.Mvc/project.json index e4d9f43429..8ceab4ef72 100644 --- a/src/Microsoft.AspNet.Mvc/project.json +++ b/src/Microsoft.AspNet.Mvc/project.json @@ -19,6 +19,8 @@ "k10": { "dependencies": { "System.Diagnostics.Debug": "4.0.10.0", + "System.Linq": "4.0.0.0", + "System.Reflection": "4.0.10.0", "System.Runtime": "4.0.20.0", "System.Runtime.Extensions": "4.0.10.0" } diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Internal/TypeExtensionTests.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Internal/TypeExtensionTests.cs deleted file mode 100644 index de7cc8532b..0000000000 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Internal/TypeExtensionTests.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using Xunit; - -namespace Microsoft.AspNet.Mvc.ModelBinding.Internal.Test -{ - public class TypeExtensionTests - { - [Theory] - [InlineData(typeof(decimal))] - [InlineData(typeof(Guid))] - public void IsCompatibleWithReturnsFalse_IfValueTypeIsNull(Type type) - { - // Act - bool result = TypeExtensions.IsCompatibleWith(type, value: null); - - // Assert - Assert.False(result); - } - - [Theory] - [InlineData(typeof(short))] - [InlineData(typeof(DateTimeOffset))] - [InlineData(typeof(Foo))] - public void IsCompatibleWithReturnsFalse_IfValueIsMismatched(Type type) - { - // Act - bool result = TypeExtensions.IsCompatibleWith(type, value: "Hello world"); - - // Assert - Assert.False(result); - } - - public static IEnumerable TypesWithValues - { - get - { - yield return new object[] { typeof(int?), null }; - yield return new object[] { typeof(int), 4 }; - yield return new object[] { typeof(int?), 1 }; - yield return new object[] { typeof(DateTime?), null }; - yield return new object[] { typeof(Guid), Guid.Empty }; - yield return new object[] { typeof(DateTimeOffset?), DateTimeOffset.UtcNow }; - yield return new object[] { typeof(string), null }; - yield return new object[] { typeof(string), "foo string" }; - yield return new object[] { typeof(Foo), null }; - yield return new object[] { typeof(Foo), new Foo() }; - } - } - - [Theory] - [MemberData("TypesWithValues")] - public void IsCompatibleWithReturnsTrue_IfValueIsAssignable(Type type, object value) - { - // Act - bool result = TypeExtensions.IsCompatibleWith(type, value); - - // Assert - Assert.True(result); - } - - private class Foo - { - } - } -}