-
-
Notifications
You must be signed in to change notification settings - Fork 231
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Methods should only be callable on predefined types (#669)
* Methods should only be callable on predefined types * add test * ip
- Loading branch information
Showing
8 changed files
with
1,737 additions
and
1,605 deletions.
There are no files selected for viewing
56 changes: 27 additions & 29 deletions
56
src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,36 @@ | ||
using JetBrains.Annotations; | ||
using System.Collections.Generic; | ||
using System.Collections.Generic; | ||
using System.Reflection; | ||
|
||
namespace System.Linq.Dynamic.Core.CustomTypeProviders | ||
namespace System.Linq.Dynamic.Core.CustomTypeProviders; | ||
|
||
/// <summary> | ||
/// Interface for providing functionality to find custom types for or resolve any type. | ||
/// </summary> | ||
public interface IDynamicLinqCustomTypeProvider | ||
{ | ||
/// <summary> | ||
/// Interface for providing functionality to find custom types for or resolve any type. | ||
/// Returns a list of custom types that System.Linq.Dynamic.Core will understand. | ||
/// </summary> | ||
public interface IDynamicLinqCustomTypeProvider | ||
{ | ||
/// <summary> | ||
/// Returns a list of custom types that System.Linq.Dynamic.Core will understand. | ||
/// </summary> | ||
/// <returns>A <see cref="HashSet{Type}" /> list of custom types.</returns> | ||
HashSet<Type> GetCustomTypes(); | ||
/// <returns>A <see cref="HashSet{Type}" /> list of custom types.</returns> | ||
HashSet<Type> GetCustomTypes(); | ||
|
||
/// <summary> | ||
/// Returns a list of custom extension methods that System.Linq.Dynamic.Core will understand. | ||
/// </summary> | ||
/// <returns>A list of custom extension methods that System.Linq.Dynamic.Core will understand.</returns> | ||
Dictionary<Type, List<MethodInfo>> GetExtensionMethods(); | ||
/// <summary> | ||
/// Returns a list of custom extension methods that System.Linq.Dynamic.Core will understand. | ||
/// </summary> | ||
/// <returns>A list of custom extension methods that System.Linq.Dynamic.Core will understand.</returns> | ||
Dictionary<Type, List<MethodInfo>> GetExtensionMethods(); | ||
|
||
/// <summary> | ||
/// Resolve any type by fullname which is registered in the current application domain. | ||
/// </summary> | ||
/// <param name="typeName">The typename to resolve.</param> | ||
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns> | ||
Type? ResolveType(string typeName); | ||
/// <summary> | ||
/// Resolve any type by fullname which is registered in the current application domain. | ||
/// </summary> | ||
/// <param name="typeName">The typename to resolve.</param> | ||
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns> | ||
Type? ResolveType(string typeName); | ||
|
||
/// <summary> | ||
/// Resolve any type by the simple name which is registered in the current application domain. | ||
/// </summary> | ||
/// <param name="simpleTypeName">The typename to resolve.</param> | ||
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns> | ||
Type? ResolveTypeBySimpleName(string simpleTypeName); | ||
} | ||
/// <summary> | ||
/// Resolve any type by the simple name which is registered in the current application domain. | ||
/// </summary> | ||
/// <param name="simpleTypeName">The typename to resolve.</param> | ||
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns> | ||
Type? ResolveTypeBySimpleName(string simpleTypeName); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
165 changes: 83 additions & 82 deletions
165
src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,108 +1,109 @@ | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Linq.Dynamic.Core.Validation; | ||
using System.Text.RegularExpressions; | ||
|
||
namespace System.Linq.Dynamic.Core.Parser | ||
namespace System.Linq.Dynamic.Core.Parser; | ||
|
||
internal static class PredefinedTypesHelper | ||
{ | ||
internal static class PredefinedTypesHelper | ||
{ | ||
private static readonly string Version = Regex.Match(typeof(PredefinedTypesHelper).AssemblyQualifiedName, @"\d+\.\d+\.\d+\.\d+").ToString(); | ||
#if NETSTANDARD2_0 | ||
private static readonly string Version = Text.RegularExpressions.Regex.Match(typeof(PredefinedTypesHelper).AssemblyQualifiedName!, @"\d+\.\d+\.\d+\.\d+").ToString(); | ||
#endif | ||
|
||
// These shorthands have different name than actual type and therefore not recognized by default from the PredefinedTypes. | ||
public static readonly IDictionary<string, Type> PredefinedTypesShorthands = new Dictionary<string, Type> | ||
{ | ||
{ "int", typeof(int) }, | ||
{ "uint", typeof(uint) }, | ||
{ "short", typeof(short) }, | ||
{ "ushort", typeof(ushort) }, | ||
{ "long", typeof(long) }, | ||
{ "ulong", typeof(ulong) }, | ||
{ "bool", typeof(bool) }, | ||
{ "float", typeof(float) } | ||
}; | ||
// These shorthands have different name than actual type and therefore not recognized by default from the PredefinedTypes. | ||
public static readonly IDictionary<string, Type> PredefinedTypesShorthands = new Dictionary<string, Type> | ||
{ | ||
{ "int", typeof(int) }, | ||
{ "uint", typeof(uint) }, | ||
{ "short", typeof(short) }, | ||
{ "ushort", typeof(ushort) }, | ||
{ "long", typeof(long) }, | ||
{ "ulong", typeof(ulong) }, | ||
{ "bool", typeof(bool) }, | ||
{ "float", typeof(float) } | ||
}; | ||
|
||
public static readonly IDictionary<Type, int> PredefinedTypes = new ConcurrentDictionary<Type, int>(new Dictionary<Type, int> { | ||
{ typeof(object), 0 }, | ||
{ typeof(bool), 0 }, | ||
{ typeof(char), 0 }, | ||
{ typeof(string), 0 }, | ||
{ typeof(sbyte), 0 }, | ||
{ typeof(byte), 0 }, | ||
{ typeof(short), 0 }, | ||
{ typeof(ushort), 0 }, | ||
{ typeof(int), 0 }, | ||
{ typeof(uint), 0 }, | ||
{ typeof(long), 0 }, | ||
{ typeof(ulong), 0 }, | ||
{ typeof(float), 0 }, | ||
{ typeof(double), 0 }, | ||
{ typeof(decimal), 0 }, | ||
{ typeof(DateTime), 0 }, | ||
{ typeof(DateTimeOffset), 0 }, | ||
{ typeof(TimeSpan), 0 }, | ||
{ typeof(Guid), 0 }, | ||
{ typeof(Math), 0 }, | ||
{ typeof(Convert), 0 }, | ||
{ typeof(Uri), 0 }, | ||
public static readonly IDictionary<Type, int> PredefinedTypes = new ConcurrentDictionary<Type, int>(new Dictionary<Type, int> { | ||
{ typeof(object), 0 }, | ||
{ typeof(bool), 0 }, | ||
{ typeof(char), 0 }, | ||
{ typeof(string), 0 }, | ||
{ typeof(sbyte), 0 }, | ||
{ typeof(byte), 0 }, | ||
{ typeof(short), 0 }, | ||
{ typeof(ushort), 0 }, | ||
{ typeof(int), 0 }, | ||
{ typeof(uint), 0 }, | ||
{ typeof(long), 0 }, | ||
{ typeof(ulong), 0 }, | ||
{ typeof(float), 0 }, | ||
{ typeof(double), 0 }, | ||
{ typeof(decimal), 0 }, | ||
{ typeof(DateTime), 0 }, | ||
{ typeof(DateTimeOffset), 0 }, | ||
{ typeof(TimeSpan), 0 }, | ||
{ typeof(Guid), 0 }, | ||
{ typeof(Math), 0 }, | ||
{ typeof(Convert), 0 }, | ||
{ typeof(Uri), 0 }, | ||
#if NET6_0_OR_GREATER | ||
{ typeof(DateOnly), 0 }, | ||
{ typeof(TimeOnly), 0 } | ||
{ typeof(DateOnly), 0 }, | ||
{ typeof(TimeOnly), 0 } | ||
#endif | ||
}); | ||
}); | ||
|
||
static PredefinedTypesHelper() | ||
{ | ||
static PredefinedTypesHelper() | ||
{ | ||
#if !(NET35 || SILVERLIGHT || NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) | ||
//System.Data.Entity is always here, so overwrite short name of it with EntityFramework if EntityFramework is found. | ||
//EF5(or 4.x??), System.Data.Objects.DataClasses.EdmFunctionAttribute | ||
//There is also an System.Data.Entity, Version=3.5.0.0, but no Functions. | ||
TryAdd("System.Data.Objects.EntityFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); | ||
TryAdd("System.Data.Objects.SqlClient.SqlFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); | ||
TryAdd("System.Data.Objects.SqlClient.SqlSpatialFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); | ||
//System.Data.Entity is always here, so overwrite short name of it with EntityFramework if EntityFramework is found. | ||
//EF5(or 4.x??), System.Data.Objects.DataClasses.EdmFunctionAttribute | ||
//There is also an System.Data.Entity, Version=3.5.0.0, but no Functions. | ||
TryAdd("System.Data.Objects.EntityFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); | ||
TryAdd("System.Data.Objects.SqlClient.SqlFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); | ||
TryAdd("System.Data.Objects.SqlClient.SqlSpatialFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); | ||
|
||
//EF6,System.Data.Entity.DbFunctionAttribute | ||
TryAdd("System.Data.Entity.Core.Objects.EntityFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
TryAdd("System.Data.Entity.DbFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
TryAdd("System.Data.Entity.Spatial.DbGeography, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
TryAdd("System.Data.Entity.SqlServer.SqlFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
TryAdd("System.Data.Entity.SqlServer.SqlSpatialFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
//EF6,System.Data.Entity.DbFunctionAttribute | ||
TryAdd("System.Data.Entity.Core.Objects.EntityFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
TryAdd("System.Data.Entity.DbFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
TryAdd("System.Data.Entity.Spatial.DbGeography, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
TryAdd("System.Data.Entity.SqlServer.SqlFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
TryAdd("System.Data.Entity.SqlServer.SqlSpatialFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); | ||
#endif | ||
|
||
#if NETSTANDARD2_0 | ||
TryAdd($"Microsoft.EntityFrameworkCore.DynamicLinq.DynamicFunctions, Microsoft.EntityFrameworkCore.DynamicLinq, Version={Version}, Culture=neutral, PublicKeyToken=974e7e1b462f3693", 3); | ||
TryAdd($"Microsoft.EntityFrameworkCore.DynamicLinq.DynamicFunctions, Microsoft.EntityFrameworkCore.DynamicLinq, Version={Version}, Culture=neutral, PublicKeyToken=974e7e1b462f3693", 3); | ||
#endif | ||
} | ||
} | ||
|
||
private static void TryAdd(string typeName, int x) | ||
private static void TryAdd(string typeName, int x) | ||
{ | ||
try | ||
{ | ||
try | ||
var efType = Type.GetType(typeName); | ||
if (efType != null) | ||
{ | ||
Type? efType = Type.GetType(typeName); | ||
if (efType != null) | ||
{ | ||
PredefinedTypes.Add(efType, x); | ||
} | ||
} | ||
catch | ||
{ | ||
// in case of exception, do not add | ||
PredefinedTypes.Add(efType, x); | ||
} | ||
} | ||
|
||
public static bool IsPredefinedType(ParsingConfig config, Type type) | ||
catch | ||
{ | ||
Check.NotNull(config, nameof(config)); | ||
Check.NotNull(type, nameof(type)); | ||
// in case of exception, do not add | ||
} | ||
} | ||
|
||
var nonNullableType = TypeHelper.GetNonNullableType(type); | ||
if (PredefinedTypes.ContainsKey(nonNullableType)) | ||
{ | ||
return true; | ||
} | ||
public static bool IsPredefinedType(ParsingConfig config, Type type) | ||
{ | ||
Check.NotNull(config); | ||
Check.NotNull(type); | ||
|
||
return config.CustomTypeProvider != null && | ||
(config.CustomTypeProvider.GetCustomTypes().Contains(type) || config.CustomTypeProvider.GetCustomTypes().Contains(nonNullableType)); | ||
var nonNullableType = TypeHelper.GetNonNullableType(type); | ||
if (PredefinedTypes.ContainsKey(nonNullableType)) | ||
{ | ||
return true; | ||
} | ||
|
||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract | ||
return config.CustomTypeProvider != null && | ||
(config.CustomTypeProvider.GetCustomTypes().Contains(type) || config.CustomTypeProvider.GetCustomTypes().Contains(nonNullableType)); | ||
} | ||
} | ||
} |
Oops, something went wrong.