diff --git a/System.Linq.Dynamic.Core.sln b/System.Linq.Dynamic.Core.sln
index 60d593a1..4506baf8 100644
--- a/System.Linq.Dynamic.Core.sln
+++ b/System.Linq.Dynamic.Core.sln
@@ -74,7 +74,12 @@ Project("{7CF6DF6D-3B04-46F8-A40B-537D21BCA0B4}") = "System.Linq.Dynamic.Core",
{D3804228-91F4-4502-9595-39584E510002} = {D3804228-91F4-4502-9595-39584E510002}
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleAppPerformanceTest236", "src-console\ConsoleAppPerformanceTest236\ConsoleAppPerformanceTest236.csproj", "{E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}"
+EndProject
Global
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
@@ -388,6 +393,22 @@ Global
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Release|x64.Build.0 = Release|Any CPU
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Release|x86.ActiveCfg = Release|Any CPU
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF}.Release|x86.Build.0 = Release|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Debug|ARM.Build.0 = Debug|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Debug|x64.Build.0 = Debug|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Debug|x86.Build.0 = Debug|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Release|ARM.ActiveCfg = Release|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Release|ARM.Build.0 = Release|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Release|x64.ActiveCfg = Release|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Release|x64.Build.0 = Release|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Release|x86.ActiveCfg = Release|Any CPU
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -412,6 +433,7 @@ Global
{F1880F07-238F-4A3A-9E58-141350665E1F} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62}
{926D446C-8358-465A-AFAC-2F9078C22262} = {ECA5702B-5D32-4888-A34E-9461FC533F23}
{591F9224-A8D6-49CF-8AF8-F9B383C1F9FF} = {1384C18E-DCF3-4A5B-9560-2BF5DD8C51CE}
+ {E9C52E5E-28DC-4D45-B9AB-1B2CF2924A84} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {94C56722-194E-4B8B-BC23-B3F754E89A20}
diff --git a/src-console/ConsoleAppPerformanceTest236/ConsoleAppPerformanceTest236.csproj b/src-console/ConsoleAppPerformanceTest236/ConsoleAppPerformanceTest236.csproj
new file mode 100644
index 00000000..d10b7fc2
--- /dev/null
+++ b/src-console/ConsoleAppPerformanceTest236/ConsoleAppPerformanceTest236.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net472
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src-console/ConsoleAppPerformanceTest236/Program.cs b/src-console/ConsoleAppPerformanceTest236/Program.cs
new file mode 100644
index 00000000..dfec60ed
--- /dev/null
+++ b/src-console/ConsoleAppPerformanceTest236/Program.cs
@@ -0,0 +1,11 @@
+namespace ConsoleAppPerformanceTest236
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Test.DoIt();
+ int x = 0;
+ }
+ }
+}
diff --git a/src-console/ConsoleAppPerformanceTest236/Report-net472-after.diagsession b/src-console/ConsoleAppPerformanceTest236/Report-net472-after.diagsession
new file mode 100644
index 00000000..6b285cbb
Binary files /dev/null and b/src-console/ConsoleAppPerformanceTest236/Report-net472-after.diagsession differ
diff --git a/src-console/ConsoleAppPerformanceTest236/Test.cs b/src-console/ConsoleAppPerformanceTest236/Test.cs
new file mode 100644
index 00000000..331a7159
--- /dev/null
+++ b/src-console/ConsoleAppPerformanceTest236/Test.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+
+namespace ConsoleAppPerformanceTest236
+{
+ public static class Test
+ {
+ public static void DoIt()
+ {
+ var q = User.GenerateSampleModels(10000).AsQueryable();
+
+ int count = 100;
+ for (int i = 0; i <= count; i++)
+ {
+ if (i % 10 == 0)
+ {
+ Console.WriteLine(i);
+ }
+ var result = q.OrderBy("FullName ASC, City DESC").FirstOrDefault();
+ }
+ }
+ }
+}
diff --git a/src-console/ConsoleAppPerformanceTest236/User.cs b/src-console/ConsoleAppPerformanceTest236/User.cs
new file mode 100644
index 00000000..4123f3c3
--- /dev/null
+++ b/src-console/ConsoleAppPerformanceTest236/User.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using RandomDataGenerator.FieldOptions;
+using RandomDataGenerator.Randomizers;
+
+namespace ConsoleAppPerformanceTest236
+{
+ public class User
+ {
+ public Guid Id { get; set; }
+
+ public string FullName { get; set; }
+
+ public string City { get; set; }
+
+ public int? NullableInt { get; set; }
+
+ public int Income { get; set; }
+
+ public static IList GenerateSampleModels(int total, bool allowNullableProfiles = false)
+ {
+ var list = new List();
+
+ var randomizerFullName = RandomizerFactory.GetRandomizer(new FieldOptionsFullName());
+ var randomizerCity= RandomizerFactory.GetRandomizer(new FieldOptionsCity());
+
+ for (int i = 0; i < total; i++)
+ {
+ var user = new User
+ {
+ Id = Guid.NewGuid(),
+ FullName = randomizerFullName.Generate(),
+ City = randomizerCity.Generate(),
+ Income = 1 + i % 15 * 100
+ };
+
+ list.Add(user);
+ }
+
+ return list.ToArray();
+ }
+ }
+}
diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs
index afeb3d3b..40e25650 100644
--- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs
+++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs
@@ -1,33 +1,27 @@
using JetBrains.Annotations;
using System.Collections.Generic;
-using System.Reflection;
using System.Linq.Dynamic.Core.Validation;
+using System.Reflection;
namespace System.Linq.Dynamic.Core.CustomTypeProviders
{
///
- /// The abstract DynamicLinqCustomTypeProvider which is used by the and can be used by a custom TypeProvider like in .NET Core.
+ /// The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core.
///
public abstract class AbstractDynamicLinqCustomTypeProvider
{
///
- /// Finds the types marked with DynamicLinqTypeAttribute.
+ /// Finds the unique types marked with DynamicLinqTypeAttribute.
///
/// The assemblies to process.
- /// IEnumerable{Type}
+ ///
protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies)
{
Check.NotNull(assemblies, nameof(assemblies));
#if !NET35
- assemblies = assemblies.Where(x => !x.IsDynamic);
-#endif
- var definedTypes = GetAssemblyTypes(assemblies);
-
-#if (WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD)
- return definedTypes.Where(x => x.CustomAttributes.Any(y => y.AttributeType == typeof(DynamicLinqTypeAttribute))).Select(x => x.AsType());
-#else
- return definedTypes.Where(x => x.GetCustomAttributes(typeof(DynamicLinqTypeAttribute), false).Any());
+ assemblies = assemblies.Where(a => !a.IsDynamic);
#endif
+ return GetAssemblyTypesWithDynamicLinqTypeAttribute(assemblies).Distinct().ToArray();
}
///
@@ -41,7 +35,7 @@ protected Type ResolveType([NotNull] IEnumerable assemblies, [NotNull]
Check.NotNull(assemblies, nameof(assemblies));
Check.NotEmpty(typeName, nameof(typeName));
- foreach (Assembly assembly in assemblies)
+ foreach (var assembly in assemblies)
{
Type resolvedType = assembly.GetType(typeName, false, true);
if (resolvedType != null)
@@ -55,28 +49,32 @@ protected Type ResolveType([NotNull] IEnumerable assemblies, [NotNull]
#if (WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD)
///
- /// Gets the assembly types in an Exception friendly way.
+ /// Gets the assembly types annotated with in an Exception friendly way.
///
/// The assemblies to process.
- /// IEnumerable{Type}
- protected IEnumerable GetAssemblyTypes([NotNull] IEnumerable assemblies)
+ ///
+ protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies)
{
Check.NotNull(assemblies, nameof(assemblies));
foreach (var assembly in assemblies)
{
- IEnumerable definedTypes = null;
+ Type[] definedTypes = null;
try
{
- definedTypes = assembly.DefinedTypes;
+ definedTypes = assembly.ExportedTypes.Where(t => t.GetTypeInfo().IsDefined(typeof(DynamicLinqTypeAttribute), false)).ToArray();
+ }
+ catch (ReflectionTypeLoadException reflectionTypeLoadException)
+ {
+ definedTypes = reflectionTypeLoadException.Types;
}
catch
{
- // Ignore error
+ // Ignore all other exceptions
}
- if (definedTypes != null)
+ if (definedTypes != null && definedTypes.Length > 0)
{
foreach (var definedType in definedTypes)
{
@@ -87,28 +85,33 @@ protected IEnumerable GetAssemblyTypes([NotNull] IEnumerable
}
#else
///
- /// Gets the assembly types in an Exception friendly way.
+ /// Gets the assembly types annotated with in an Exception friendly way.
///
/// The assemblies to process.
- /// IEnumerable{Type}
- protected IEnumerable GetAssemblyTypes([NotNull] IEnumerable assemblies)
+ ///
+ protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies)
{
Check.NotNull(assemblies, nameof(assemblies));
- foreach (var assembly in assemblies)
+ foreach (var assembly in assemblies.Where(a => !a.GlobalAssemblyCache)) // Skip System DLL's
{
- IEnumerable definedTypes = null;
+ Type[] definedTypes = null;
try
{
- definedTypes = assembly.GetTypes();
+ definedTypes = assembly.GetExportedTypes()
+ .Where(t => t.IsDefined(typeof(DynamicLinqTypeAttribute), false)).ToArray();
+ }
+ catch (ReflectionTypeLoadException reflectionTypeLoadException)
+ {
+ definedTypes = reflectionTypeLoadException.Types;
}
catch
{
- // Ignore error
+ // Ignore all other exceptions
}
- if (definedTypes != null)
+ if (definedTypes != null && definedTypes.Length > 0)
{
foreach (var definedType in definedTypes)
{
diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs
index d51c7f6f..ad91dc39 100644
--- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs
+++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs
@@ -1,12 +1,12 @@
-#if !(WINDOWS_APP || UAP10_0)
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq.Dynamic.Core.Validation;
using System.Reflection;
namespace System.Linq.Dynamic.Core.CustomTypeProviders
{
///
- /// The default .
+ /// The default implementation for .
+ ///
/// Scans the current AppDomain for all types marked with , and adds them as custom Dynamic Link types.
///
/// Also provides functionality to resolve a Type in the current Application Domain.
@@ -16,12 +16,33 @@ namespace System.Linq.Dynamic.Core.CustomTypeProviders
public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
{
private readonly IAssemblyHelper _assemblyHelper = new DefaultAssemblyHelper();
+ private readonly bool _cacheCustomTypes;
+
+ private HashSet _cachedCustomTypes;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Defines whether to cache the CustomTypes which are found in the Application Domain. Default set to 'true'.
+ public DefaultDynamicLinqCustomTypeProvider(bool cacheCustomTypes = true)
+ {
+ _cacheCustomTypes = cacheCustomTypes;
+ }
///
public virtual HashSet GetCustomTypes()
{
- IEnumerable assemblies = _assemblyHelper.GetAssemblies();
- return new HashSet(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
+ if (_cacheCustomTypes)
+ {
+ if (_cachedCustomTypes == null)
+ {
+ _cachedCustomTypes = GetCustomTypesInternal();
+ }
+
+ return _cachedCustomTypes;
+ }
+
+ return GetCustomTypesInternal();
}
///
@@ -32,6 +53,11 @@ public Type ResolveType(string typeName)
IEnumerable assemblies = _assemblyHelper.GetAssemblies();
return ResolveType(assemblies, typeName);
}
+
+ private HashSet GetCustomTypesInternal()
+ {
+ IEnumerable assemblies = _assemblyHelper.GetAssemblies();
+ return new HashSet(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
+ }
}
}
-#endif
diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinkCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinkCustomTypeProvider.cs
index 49e355be..a56a9a93 100644
--- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinkCustomTypeProvider.cs
+++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinkCustomTypeProvider.cs
@@ -1,5 +1,5 @@
-using System.Collections.Generic;
-using JetBrains.Annotations;
+using JetBrains.Annotations;
+using System.Collections.Generic;
namespace System.Linq.Dynamic.Core.CustomTypeProviders
{
@@ -11,7 +11,7 @@ public interface IDynamicLinkCustomTypeProvider
///
/// Returns a list of custom types that System.Linq.Dynamic.Core will understand.
///
- /// A list of custom types.
+ /// A list of custom types.
HashSet GetCustomTypes();
///
diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
index f884bda1..66b0280b 100644
--- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
+++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
@@ -1564,7 +1564,7 @@ Type FindType(string name)
{
_keywordsHelper.TryGetValue(name, out object type);
- var result = type as Type;
+ Type result = type as Type;
if (result != null)
{
return result;
@@ -1584,6 +1584,7 @@ Type FindType(string name)
{
return _root.Type;
}
+
if (_it != null && _it.Type.Namespace + "." + _it.Type.Name == name)
{
return _it.Type;
diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs
index 84741f21..a86562a9 100644
--- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs
+++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs
@@ -35,7 +35,7 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider
get
{
#if !(DOTNET5_1 || WINDOWS_APP || UAP10_0 || NETSTANDARD)
- // only use DefaultDynamicLinqCustomTypeProvider if not WINDOWS_APP || UAP10_0 || NETSTANDARD
+ // only use DefaultDynamicLinqCustomTypeProvider for full .NET Framework
return _customTypeProvider ?? (_customTypeProvider = new DefaultDynamicLinqCustomTypeProvider());
#else
return _customTypeProvider;
diff --git a/test/EntityFramework.DynamicLinq.Tests.net452/EntityFramework.DynamicLinq.Tests.net452.csproj b/test/EntityFramework.DynamicLinq.Tests.net452/EntityFramework.DynamicLinq.Tests.net452.csproj
index effb692b..4b471b46 100644
--- a/test/EntityFramework.DynamicLinq.Tests.net452/EntityFramework.DynamicLinq.Tests.net452.csproj
+++ b/test/EntityFramework.DynamicLinq.Tests.net452/EntityFramework.DynamicLinq.Tests.net452.csproj
@@ -64,8 +64,8 @@
..\..\packages\Moq.4.10.0\lib\net45\Moq.dll
-
- ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
+
+ ..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
..\..\packages\NFluent.2.1.1\lib\net45\NFluent.dll
diff --git a/test/EntityFramework.DynamicLinq.Tests.net452/packages.config b/test/EntityFramework.DynamicLinq.Tests.net452/packages.config
index cd072130..e5dd8b28 100644
--- a/test/EntityFramework.DynamicLinq.Tests.net452/packages.config
+++ b/test/EntityFramework.DynamicLinq.Tests.net452/packages.config
@@ -9,7 +9,7 @@
-
+
diff --git a/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj b/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj
index f390dffb..5285cf81 100644
--- a/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj
+++ b/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj
@@ -34,7 +34,7 @@
-
+
diff --git a/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj b/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj
index 22101e05..8790911c 100644
--- a/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj
+++ b/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj
@@ -30,7 +30,7 @@
all
runtime; build; native; contentfiles; analyzers
-
+