Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions System.Linq.Dynamic.Core.sln
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.EntityFrameworkCo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Linq.Dynamic.Core.Tests.Net8", "test\System.Linq.Dynamic.Core.Tests.Net8\System.Linq.Dynamic.Core.Tests.Net8.csproj", "{CEBE3A33-4814-42A4-BD8E-F7F2308A4C8C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleAppPerformanceTest", "src-console\ConsoleAppPerformanceTest\ConsoleAppPerformanceTest.csproj", "{067C00CF-29FA-4643-814D-3A3C3C84634F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1039,6 +1041,22 @@ Global
{CEBE3A33-4814-42A4-BD8E-F7F2308A4C8C}.Release|x64.Build.0 = Release|Any CPU
{CEBE3A33-4814-42A4-BD8E-F7F2308A4C8C}.Release|x86.ActiveCfg = Release|Any CPU
{CEBE3A33-4814-42A4-BD8E-F7F2308A4C8C}.Release|x86.Build.0 = Release|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Debug|ARM.ActiveCfg = Debug|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Debug|ARM.Build.0 = Debug|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Debug|x64.ActiveCfg = Debug|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Debug|x64.Build.0 = Debug|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Debug|x86.ActiveCfg = Debug|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Debug|x86.Build.0 = Debug|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Release|Any CPU.Build.0 = Release|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Release|ARM.ActiveCfg = Release|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Release|ARM.Build.0 = Release|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Release|x64.ActiveCfg = Release|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Release|x64.Build.0 = Release|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Release|x86.ActiveCfg = Release|Any CPU
{067C00CF-29FA-4643-814D-3A3C3C84634F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1098,6 +1116,7 @@ Global
{7A31366C-DD98-41A3-A0C1-A97068BD9658} = {BCA2A024-9032-4E56-A6C4-17A15D921728}
{C774DAE7-54A0-4FCD-A3B7-3CB63D7E112D} = {DBD7D9B6-FCC7-4650-91AF-E6457573A68F}
{CEBE3A33-4814-42A4-BD8E-F7F2308A4C8C} = {8463ED7E-69FB-49AE-85CF-0791AFD98E38}
{067C00CF-29FA-4643-814D-3A3C3C84634F} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {94C56722-194E-4B8B-BC23-B3F754E89A20}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net48</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>12</LangVersion>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\System.Linq.Dynamic.Core\System.Linq.Dynamic.Core.csproj" />
</ItemGroup>

</Project>
32 changes: 32 additions & 0 deletions src-console/ConsoleAppPerformanceTest/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Linq.Dynamic.Core;

TestDynamic();
return;

static void TestDynamic()
{
var list = new List<Demo>();
for (int i = 0; i < 100000; i++)
{
list.Add(new Demo { ID = i, Name = $"Name {i}", Description = $"Description {i}" });
}

var xTimeAll = System.Diagnostics.Stopwatch.StartNew();
var query = list.AsQueryable().Select(typeof(Demo), "new { ID, Name }").ToDynamicList();
Console.WriteLine($"Total 1st Query: {(int)xTimeAll.Elapsed.TotalMilliseconds}ms");

xTimeAll.Restart();
_ = query.AsQueryable().Select("ID").Cast<int>().ToList();
Console.WriteLine($"Total nd Query: {(int)xTimeAll.Elapsed.TotalMilliseconds}ms");

xTimeAll.Restart();
_ = query.AsQueryable().Select("new { it.ID as Idee } ").ToDynamicList();
Console.WriteLine($"Total 3rd Query: {(int)xTimeAll.Elapsed.TotalMilliseconds}ms");
}

class Demo
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
20 changes: 17 additions & 3 deletions src/System.Linq.Dynamic.Core/DynamicGetMemberBinder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#if !NET35 && !UAP10_0 && !NETSTANDARD1_3
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq.Expressions;
Expand All @@ -14,8 +15,9 @@ namespace System.Linq.Dynamic.Core;
internal class DynamicGetMemberBinder : GetMemberBinder
{
private static readonly MethodInfo DynamicGetMemberMethod = typeof(DynamicGetMemberBinder).GetMethod(nameof(GetDynamicMember))!;
private readonly ConcurrentDictionary<Tuple<Type, string, bool>, DynamicMetaObject> _metaObjectCache = new();

public DynamicGetMemberBinder(string name, ParsingConfig? config) : base(name, config?.IsCaseSensitive != true)
internal DynamicGetMemberBinder(string name, ParsingConfig? config) : base(name, config?.IsCaseSensitive != true)
{
}

Expand All @@ -28,8 +30,20 @@ public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, Dy
Expression.Constant(IgnoreCase));

// Fix #907 and #912: "The result of the dynamic binding produced by the object with type '<>f__AnonymousType1`4' for the binder 'System.Linq.Dynamic.Core.DynamicGetMemberBinder' needs at least one restriction.".
var restrictions = BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value);
return new DynamicMetaObject(methodCallExpression, restrictions, target.Value!);
// Fix #921: "Slow Performance"
// Only add TypeRestriction if it's a Dynamic type and make sure to cache the DynamicMetaObject.
if (target.Value is IDynamicMetaObjectProvider)
{
var key = new Tuple<Type, string, bool>(target.LimitType, Name, IgnoreCase);

return _metaObjectCache.GetOrAdd(key, _ =>
{
var restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType);
return new DynamicMetaObject(methodCallExpression, restrictions, target.Value);
});
}

return DynamicMetaObject.Create(target.Value!, methodCallExpression);
}

public static object? GetDynamicMember(object value, string name, bool ignoreCase)
Expand Down
Loading