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
This commit is contained in:
dougbu 2014-03-17 21:02:25 -07:00
parent a8cc6828dd
commit d534471515
9 changed files with 143 additions and 212 deletions

View File

@ -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<Type, bool> 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<T> 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;
}
}
}

View File

@ -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"
}
}

View File

@ -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<Type, bool> 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
}
}
}

View File

@ -1,5 +1,4 @@
using Microsoft.AspNet.Mvc.ModelBinding.Internal;

namespace Microsoft.AspNet.Mvc.ModelBinding
{
public sealed class ComplexModelDtoResult

View File

@ -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<T> 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;
}
}
}

View File

@ -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",

View File

@ -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",

View File

@ -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"
}

View File

@ -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<object[]> 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
{
}
}
}