From 31f6f24edaa3c3123183603d8bf77d73d26ccf4b Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 5 Oct 2015 14:33:24 -0700 Subject: [PATCH] Incremental steps to netnative support --- .../EntityFramework.Core.csproj | 1 + .../Metadata/Internal/ClrAccessorSource.cs | 16 +--- .../Internal/ClrPropertyGetterSource.cs | 11 ++- .../Internal/ClrPropertySetterSource.cs | 23 ++++-- .../Properties/EntityFramework.Core.rd.xml | 9 ++- src/EntityFramework.Core/Utilities/Imply.cs | 79 +++++++++++++++++++ .../EntityFramework.MicrosoftSqlServer.rd.xml | 2 +- .../EntityFramework.Relational.rd.xml | 25 +++++- .../Properties/EntityFramework.Sqlite.rd.xml | 2 +- 9 files changed, 140 insertions(+), 28 deletions(-) create mode 100644 src/EntityFramework.Core/Utilities/Imply.cs diff --git a/src/EntityFramework.Core/EntityFramework.Core.csproj b/src/EntityFramework.Core/EntityFramework.Core.csproj index 95e5253ee27..a7591e2147d 100644 --- a/src/EntityFramework.Core/EntityFramework.Core.csproj +++ b/src/EntityFramework.Core/EntityFramework.Core.csproj @@ -414,6 +414,7 @@ Extensions\Internal\SharedTypeExtensions.cs + diff --git a/src/EntityFramework.Core/Metadata/Internal/ClrAccessorSource.cs b/src/EntityFramework.Core/Metadata/Internal/ClrAccessorSource.cs index 2083ff528f0..8767e301316 100644 --- a/src/EntityFramework.Core/Metadata/Internal/ClrAccessorSource.cs +++ b/src/EntityFramework.Core/Metadata/Internal/ClrAccessorSource.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Linq; using System.Reflection; using JetBrains.Annotations; using Microsoft.Data.Entity.Internal; @@ -12,9 +11,6 @@ namespace Microsoft.Data.Entity.Metadata.Internal public abstract class ClrAccessorSource : IClrAccessorSource where TAccessor : class { - private static readonly MethodInfo _genericCreate - = typeof(ClrAccessorSource).GetTypeInfo().GetDeclaredMethods("CreateGeneric").Single(); - private readonly ThreadSafeDictionaryCache, TAccessor> _cache = new ThreadSafeDictionaryCache, TAccessor>(); @@ -24,13 +20,9 @@ public virtual TAccessor GetAccessor(IPropertyBase property) public virtual TAccessor GetAccessor(Type declaringType, string propertyName) => _cache.GetOrAdd(Tuple.Create(declaringType, propertyName), k => Create(k.Item1.GetAnyProperty(k.Item2))); - private TAccessor Create(PropertyInfo property) - { - var boundMethod = _genericCreate.MakeGenericMethod(property.DeclaringType, property.PropertyType, property.PropertyType.UnwrapNullableType()); - - return (TAccessor)boundMethod.Invoke(this, new object[] { property }); - } - - protected abstract TAccessor CreateGeneric([NotNull] PropertyInfo property) where TEntity : class; + // TODO revisit when .NET Native supports ImpliesMethodInstantiation + // original version used generics, which is much cleaner and performant but fails after ILC strips reflection info + // https://github.com/aspnet/EntityFramework/issues/3477 + protected abstract TAccessor Create([NotNull] PropertyInfo property); } } diff --git a/src/EntityFramework.Core/Metadata/Internal/ClrPropertyGetterSource.cs b/src/EntityFramework.Core/Metadata/Internal/ClrPropertyGetterSource.cs index 130b8717d50..3b25c4ddac6 100644 --- a/src/EntityFramework.Core/Metadata/Internal/ClrPropertyGetterSource.cs +++ b/src/EntityFramework.Core/Metadata/Internal/ClrPropertyGetterSource.cs @@ -3,13 +3,18 @@ using System; using System.Reflection; +using JetBrains.Annotations; namespace Microsoft.Data.Entity.Metadata.Internal { public class ClrPropertyGetterSource : ClrAccessorSource { - protected override IClrPropertyGetter CreateGeneric(PropertyInfo property) - => new ClrPropertyGetter( - (Func)property.GetMethod.CreateDelegate(typeof(Func))); + protected override IClrPropertyGetter Create([NotNull] PropertyInfo property) + { + var types = new[] { property.DeclaringType, property.PropertyType }; + var getterType = typeof(ClrPropertyGetter<,>).MakeGenericType(types); + var funcType = typeof(Func<,>).MakeGenericType(types); + return (IClrPropertyGetter)Activator.CreateInstance(getterType, property.GetMethod.CreateDelegate(funcType)); + } } } diff --git a/src/EntityFramework.Core/Metadata/Internal/ClrPropertySetterSource.cs b/src/EntityFramework.Core/Metadata/Internal/ClrPropertySetterSource.cs index 5d506748e53..331321598fa 100644 --- a/src/EntityFramework.Core/Metadata/Internal/ClrPropertySetterSource.cs +++ b/src/EntityFramework.Core/Metadata/Internal/ClrPropertySetterSource.cs @@ -3,21 +3,32 @@ using System; using System.Reflection; +using JetBrains.Annotations; namespace Microsoft.Data.Entity.Metadata.Internal { public class ClrPropertySetterSource : ClrAccessorSource { - protected override IClrPropertySetter CreateGeneric(PropertyInfo property) + protected override IClrPropertySetter Create([NotNull] PropertyInfo property) { // TODO: Handle case where there is not setter or setter is private on a base type // Issue #753 - var setterDelegate = (Action)property.SetMethod.CreateDelegate(typeof(Action)); - return (property.PropertyType.IsNullableType() - && property.PropertyType.UnwrapNullableType().GetTypeInfo().IsEnum) ? - new NullableEnumClrPropertySetter(setterDelegate) : - (IClrPropertySetter)new ClrPropertySetter(setterDelegate); + var types = new[] { property.DeclaringType, property.PropertyType }; + var actionType = typeof(Action<,>).MakeGenericType(types); + + Type setterType; + if (property.PropertyType.IsNullableType() + && property.PropertyType.UnwrapNullableType().GetTypeInfo().IsEnum) + { + setterType = typeof(NullableEnumClrPropertySetter<,,>).MakeGenericType(property.DeclaringType, property.PropertyType, property.PropertyType.UnwrapNullableType()); + } + else + { + setterType = typeof(ClrPropertySetter<,>).MakeGenericType(types); + } + + return (IClrPropertySetter)Activator.CreateInstance(setterType, property.SetMethod.CreateDelegate(actionType)); } } } diff --git a/src/EntityFramework.Core/Properties/EntityFramework.Core.rd.xml b/src/EntityFramework.Core/Properties/EntityFramework.Core.rd.xml index ebedb78f774..d4acf096bfc 100644 --- a/src/EntityFramework.Core/Properties/EntityFramework.Core.rd.xml +++ b/src/EntityFramework.Core/Properties/EntityFramework.Core.rd.xml @@ -1,7 +1,14 @@ - + + + + + + + + \ No newline at end of file diff --git a/src/EntityFramework.Core/Utilities/Imply.cs b/src/EntityFramework.Core/Utilities/Imply.cs new file mode 100644 index 00000000000..9ed43b6ac0b --- /dev/null +++ b/src/EntityFramework.Core/Utilities/Imply.cs @@ -0,0 +1,79 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#pragma warning disable 0169 + +using Microsoft.Data.Entity.Storage; +using System; +using Microsoft.Data.Entity.ChangeTracking.Internal; +using Microsoft.Data.Entity.Metadata.Internal; + +namespace Microsoft.Data.Entity.Utilities +{ + // This code exists only to trick the ILC compliation to include metadata + // about combinations of entity types and our internal types. + // This is the jumping off point for a reasoning about what generic types + // may exist at runtime. + // https://github.com/aspnet/EntityFramework/issues/3477 + internal class ImpliedEntityType + where TEntity : class + { + InternalImplyValuesAndTypes EntityValueProp; + + InternalImpliesTypes EntityProp; + InternalImpliesTypes CharProp; + InternalImpliesTypes Int16Prop; + InternalImpliesTypes UInt16Prop; + InternalImpliesTypes Int32Prop; + InternalImpliesTypes UInt32Prop; + InternalImpliesTypes Int64Prop; + InternalImpliesTypes UInt64Prop; + InternalImpliesTypes DoubleProp; + InternalImpliesTypes DecimalProp; + InternalImpliesTypes FloatProp; + InternalImpliesTypes StringProp; + InternalImpliesTypes BoolProp; + InternalImpliesTypes ByteProp; + InternalImpliesTypes GuidProp; + InternalImpliesTypes TimeSpanProp; + InternalImpliesTypes DateTimeProp; + InternalImpliesTypes DateTimeOffsetProp; + } + + internal class InternalImpliesTypes + { + void CompileQuery() + => ((IDatabase)new object()).CompileQuery(null); + + SimpleEntityKeyFactory KeyFactoryType; + } + + internal class InternalImplyTypes + where TUserType : class + { + ClrPropertyGetter ClrPropertyGetter; + ClrPropertySetter ClrPropertySetter; + } + + internal class InternalImplyValuesAndTypes + where TEntity : class + { + InternalImplyTypes CharProp; + InternalImplyTypes Int16Prop; + InternalImplyTypes UInt16Prop; + InternalImplyTypes Int32Prop; + InternalImplyTypes UInt32Prop; + InternalImplyTypes Int64Prop; + InternalImplyTypes UInt64Prop; + InternalImplyTypes DoubleProp; + InternalImplyTypes DecimalProp; + InternalImplyTypes FloatProp; + InternalImplyTypes StringProp; + InternalImplyTypes BoolProp; + InternalImplyTypes ByteProp; + InternalImplyTypes GuidProp; + InternalImplyTypes TimeSpanProp; + InternalImplyTypes DateTimeProp; + InternalImplyTypes DateTimeOffsetProp; + } +} diff --git a/src/EntityFramework.MicrosoftSqlServer/Properties/EntityFramework.MicrosoftSqlServer.rd.xml b/src/EntityFramework.MicrosoftSqlServer/Properties/EntityFramework.MicrosoftSqlServer.rd.xml index 8eb60832792..c4b26f08b57 100644 --- a/src/EntityFramework.MicrosoftSqlServer/Properties/EntityFramework.MicrosoftSqlServer.rd.xml +++ b/src/EntityFramework.MicrosoftSqlServer/Properties/EntityFramework.MicrosoftSqlServer.rd.xml @@ -1,7 +1,7 @@ + - \ No newline at end of file diff --git a/src/EntityFramework.Relational/Properties/EntityFramework.Relational.rd.xml b/src/EntityFramework.Relational/Properties/EntityFramework.Relational.rd.xml index ee409e9581d..0dacc8006ab 100644 --- a/src/EntityFramework.Relational/Properties/EntityFramework.Relational.rd.xml +++ b/src/EntityFramework.Relational/Properties/EntityFramework.Relational.rd.xml @@ -2,10 +2,27 @@ - - - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/EntityFramework.Sqlite/Properties/EntityFramework.Sqlite.rd.xml b/src/EntityFramework.Sqlite/Properties/EntityFramework.Sqlite.rd.xml index f3142e38a21..b48de95c155 100644 --- a/src/EntityFramework.Sqlite/Properties/EntityFramework.Sqlite.rd.xml +++ b/src/EntityFramework.Sqlite/Properties/EntityFramework.Sqlite.rd.xml @@ -3,6 +3,6 @@ - + \ No newline at end of file