Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prototype moving JsonData to be backed by JsonDocument #33063

Merged
merged 107 commits into from
Feb 2, 2023
Merged
Show file tree
Hide file tree
Changes from 87 commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
8e43b11
Add WriteTo(), ==operators, and PR FB
annelo-msft Dec 13, 2022
b49a143
export API
annelo-msft Dec 13, 2022
74058d9
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Dec 14, 2022
bb44811
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Dec 14, 2022
a436b30
Add DocumentSentiment large JSON sample and add parse and read benchm…
annelo-msft Dec 14, 2022
5673466
initial attempt to move to JsonElement
annelo-msft Dec 14, 2022
3c35174
some fixes
annelo-msft Dec 14, 2022
136c6c3
updates
annelo-msft Dec 15, 2022
61289a7
nit
annelo-msft Dec 15, 2022
7843b4e
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Dec 15, 2022
e1be79b
nits
annelo-msft Dec 16, 2022
adc22ec
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Dec 16, 2022
eefa39a
starting to experiment with changelist approach
annelo-msft Dec 16, 2022
4a376f1
an approach to object assignment
annelo-msft Dec 16, 2022
fbe0894
start working with array elements
annelo-msft Dec 17, 2022
1e8d2eb
saving changes from before break...
annelo-msft Jan 3, 2023
499a72b
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Jan 5, 2023
3a20c5d
sm formatting pr fb
annelo-msft Jan 5, 2023
49f089a
ApiView FB per generality of DynamicData
annelo-msft Jan 5, 2023
878e431
nits
annelo-msft Jan 5, 2023
1bfe071
small thoughts
annelo-msft Jan 6, 2023
a694231
first steps toward abstracting ChangeTracker
annelo-msft Jan 6, 2023
82b5316
In flight changes while implementing AddPropertyToObject
annelo-msft Jan 6, 2023
c126dca
adding tests with simple modifications to structural elements
annelo-msft Jan 7, 2023
7094bfb
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Jan 17, 2023
e3b313b
Implementing WriteTo()
annelo-msft Jan 17, 2023
937a224
Added nested objects
annelo-msft Jan 17, 2023
aa9c666
refactor
annelo-msft Jan 17, 2023
632985e
missed changes
annelo-msft Jan 17, 2023
934ee4c
In TDD spirit, add failing WriteTo test
annelo-msft Jan 18, 2023
1dd1ef8
Test passes
annelo-msft Jan 18, 2023
9f28d81
quick refactor
annelo-msft Jan 18, 2023
26bb1b7
update add property test
annelo-msft Jan 18, 2023
21c1ab2
Merge remote-tracking branch 'upstream/main' into core-jsondata-write…
annelo-msft Jan 19, 2023
ac891c5
Update WriteTo to handle property additions at the root element
annelo-msft Jan 19, 2023
5f34ffb
Handle property additions on arbitrary objects
annelo-msft Jan 19, 2023
902df1c
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Jan 19, 2023
63f1e6d
handle standard property removals
annelo-msft Jan 19, 2023
78babed
Support Replace with object
annelo-msft Jan 19, 2023
0b21508
Support Replace with object
annelo-msft Jan 19, 2023
48a9fee
refactor where we serialize structural changes to centralize
annelo-msft Jan 20, 2023
9d0039c
Implement reference semantics for JsonDataElement
annelo-msft Jan 20, 2023
53dd7e9
experiment with checking ancestors for structural changes.
annelo-msft Jan 21, 2023
54c8c08
Update WriteTo to handle structural changes.
annelo-msft Jan 21, 2023
dd773d7
add high water mark logic
annelo-msft Jan 23, 2023
e37981d
add validation to all reads and add failing test for ignoring pre-str…
annelo-msft Jan 23, 2023
161d578
Incorporate HWM logic in all change lookups; make PriorChangeToReplac…
annelo-msft Jan 23, 2023
6d48737
remove double-check of object and array elements
annelo-msft Jan 23, 2023
e325e32
some tidy up
annelo-msft Jan 23, 2023
7ef3d9a
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Jan 23, 2023
8af0eb2
Reimplement GetProperty in terms of TryGetProperty()
annelo-msft Jan 23, 2023
7327d16
Handle WriteTo for structural changes.
annelo-msft Jan 23, 2023
336b531
add some tests of structural changes
annelo-msft Jan 24, 2023
3c5032d
refactor tests
annelo-msft Jan 24, 2023
6954115
Bug fix to WriteTo for bools and test refactoring
annelo-msft Jan 24, 2023
3b84c28
bug fix to WriteTo for booleans
annelo-msft Jan 24, 2023
2b13efb
Add support for nulls and fix ToLower() bug
annelo-msft Jan 24, 2023
62671ed
add perf benchmark prior to working on perf
annelo-msft Jan 24, 2023
1c3f34b
missed file
annelo-msft Jan 24, 2023
df84bc0
update Parse() to use Memory<byte>
annelo-msft Jan 24, 2023
f2b94d8
move subclasses to separate files for ease of reading
annelo-msft Jan 25, 2023
5097fd7
refactor to add dynamic layer
annelo-msft Jan 25, 2023
f2bd846
Add cast operators to JsonDataElement to pass dynamic GetIntProperty …
annelo-msft Jan 25, 2023
b663856
Add support for dynamic nested property access
annelo-msft Jan 25, 2023
cdad822
enable set via dynamic layer
annelo-msft Jan 25, 2023
68827c3
Enable setting nested properties via dynamic layer
annelo-msft Jan 25, 2023
5ba740e
nit
annelo-msft Jan 25, 2023
70e114a
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Jan 26, 2023
77bf7e0
Renames prior to dynamic refactor
annelo-msft Jan 26, 2023
d013932
start adding separate dynamic layer
annelo-msft Jan 26, 2023
c45eaa8
Move dynamic meta object to dyanmic types.
annelo-msft Jan 26, 2023
42543f3
API updates
annelo-msft Jan 26, 2023
70eee2b
todos and nits
annelo-msft Jan 26, 2023
ff6e123
rename test to match types
annelo-msft Jan 26, 2023
e587339
remove outer DynamicJson class
annelo-msft Jan 26, 2023
f43d141
add BindConvert to dynamic layer
annelo-msft Jan 27, 2023
eceaab5
Add BindGetIndex to dynamic layer
annelo-msft Jan 27, 2023
8d4e6ab
save multitarget attempt
annelo-msft Jan 27, 2023
049a820
Add target frameworks to Experimental to allow ifdefs by target frame…
annelo-msft Jan 27, 2023
4fd4f16
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Jan 27, 2023
e3d69c7
Merge branch 'temp_multitarget' into jsondata-perfexp1
annelo-msft Jan 27, 2023
48b0d04
PR feedback; use more efficient Deserialize call when available in Co…
annelo-msft Jan 27, 2023
b69bec5
refactor per PR fb
annelo-msft Jan 27, 2023
f5d701e
Add BindSetIndex to dynamic layer
annelo-msft Jan 27, 2023
5bfd5af
Fix bug in mutable ToString() where changes to descendants weren't ac…
annelo-msft Jan 27, 2023
20cd72e
Fix WriteTo() bug for string elements and add failing test for handli…
annelo-msft Jan 27, 2023
d9c04ea
Handle null values
annelo-msft Jan 27, 2023
3994769
PR fb
annelo-msft Jan 27, 2023
99ce0fd
Add support for floats and longs
annelo-msft Jan 27, 2023
74ccb91
remove HasValue, per pr fb
annelo-msft Jan 27, 2023
5b90d6e
export API changes
annelo-msft Jan 27, 2023
e905fb0
Support adding properties on dynamic member assignments
annelo-msft Jan 28, 2023
2858cba
reshuffle methods around
annelo-msft Jan 28, 2023
9a9d31d
some changes before adding support for IEnumerable
annelo-msft Jan 28, 2023
7edadb4
Add ArrayEnumerator to MutableJsonElement
annelo-msft Jan 31, 2023
fa3db81
missed file; dynamic portion not complete
annelo-msft Jan 31, 2023
5a6ff95
Bug fix to dynamic ArrayEnumerator; foreach over array now passes
annelo-msft Jan 31, 2023
72dafd9
export API and misc test updates
annelo-msft Feb 1, 2023
813d95f
nit; cleanup
annelo-msft Feb 1, 2023
1e0244e
Make MutableJsonDocument serializable
annelo-msft Feb 1, 2023
3fe0203
Make DynamicJson serializable; enable reference semantics for added p…
annelo-msft Feb 1, 2023
42578cb
Make tests pass for net6.0 & net7.0; will address net461 separately
annelo-msft Feb 1, 2023
be7efb4
Fixes for some net461 issues
annelo-msft Feb 2, 2023
0640de2
Fix Add and Set property for net461
annelo-msft Feb 2, 2023
1e7b9fc
Work around BindBinaryOperation in net461; move inline TODOs to GH issue
annelo-msft Feb 2, 2023
f84eed4
Export API
annelo-msft Feb 2, 2023
a29bf14
Merge remote-tracking branch 'upstream/main' into jsondata-perfexp1
annelo-msft Feb 2, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -115,52 +115,62 @@ public static partial class BinaryDataExtensions
public abstract partial class DynamicData
{
protected DynamicData() { }
internal abstract void WriteTo(System.Text.Json.Utf8JsonWriter writer);
public static void WriteTo(System.Text.Json.Utf8JsonWriter writer, Azure.Core.Dynamic.DynamicData data) { }
internal abstract void WriteTo(System.IO.Stream stream);
public static void WriteTo(System.IO.Stream stream, Azure.Core.Dynamic.DynamicData data) { }
}
[System.Diagnostics.DebuggerDisplayAttribute("{DebuggerDisplay,nq}")]
public partial class JsonData : Azure.Core.Dynamic.DynamicData, System.Dynamic.IDynamicMetaObjectProvider, System.IEquatable<Azure.Core.Dynamic.JsonData>
public partial class DynamicJson : Azure.Core.Dynamic.DynamicData, System.Dynamic.IDynamicMetaObjectProvider, System.IEquatable<Azure.Core.Dynamic.MutableJsonDocument>
{
internal JsonData() { }
public bool Equals(Azure.Core.Dynamic.JsonData other) { throw null; }
internal DynamicJson() { }
public bool Equals(Azure.Core.Dynamic.MutableJsonDocument? other) { throw null; }
public override bool Equals(object? obj) { throw null; }
public override int GetHashCode() { throw null; }
public static bool operator ==(Azure.Core.Dynamic.JsonData? left, bool right) { throw null; }
public static bool operator ==(Azure.Core.Dynamic.JsonData? left, double right) { throw null; }
public static bool operator ==(Azure.Core.Dynamic.JsonData? left, int right) { throw null; }
public static bool operator ==(Azure.Core.Dynamic.JsonData? left, long right) { throw null; }
public static bool operator ==(Azure.Core.Dynamic.JsonData? left, float right) { throw null; }
public static bool operator ==(Azure.Core.Dynamic.JsonData? left, string? right) { throw null; }
public static bool operator ==(bool left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator ==(double left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator ==(int left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator ==(long left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator ==(float left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator ==(string? left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static implicit operator bool (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator double (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator int (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator long (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator bool? (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator double? (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator int? (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator long? (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator float? (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator float (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator string (Azure.Core.Dynamic.JsonData json) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.JsonData? left, bool right) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.JsonData? left, double right) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.JsonData? left, int right) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.JsonData? left, long right) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.JsonData? left, float right) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.JsonData? left, string? right) { throw null; }
public static bool operator !=(bool left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator !=(double left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator !=(int left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator !=(long left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator !=(float left, Azure.Core.Dynamic.JsonData? right) { throw null; }
public static bool operator !=(string? left, Azure.Core.Dynamic.JsonData? right) { throw null; }
System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(System.Linq.Expressions.Expression parameter) { throw null; }
public override string ToString() { throw null; }
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial struct DynamicJsonElement : System.Dynamic.IDynamicMetaObjectProvider, System.IEquatable<Azure.Core.Dynamic.DynamicJsonElement>
{
private object _dummy;
private int _dummyPrimitive;
public bool Equals(Azure.Core.Dynamic.DynamicJsonElement other) { throw null; }
public override bool Equals(object obj) { throw null; }
public override int GetHashCode() { throw null; }
public static implicit operator bool (Azure.Core.Dynamic.DynamicJsonElement value) { throw null; }
public static implicit operator double (Azure.Core.Dynamic.DynamicJsonElement value) { throw null; }
public static implicit operator int (Azure.Core.Dynamic.DynamicJsonElement value) { throw null; }
public static implicit operator long (Azure.Core.Dynamic.DynamicJsonElement value) { throw null; }
public static implicit operator float (Azure.Core.Dynamic.DynamicJsonElement value) { throw null; }
public static implicit operator string? (Azure.Core.Dynamic.DynamicJsonElement value) { throw null; }
System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(System.Linq.Expressions.Expression parameter) { throw null; }
}
[System.Text.Json.Serialization.JsonConverterAttribute(typeof(System.Text.Json.Serialization.JsonConverter))]
public partial class MutableJsonDocument
{
internal MutableJsonDocument() { }
public Azure.Core.Dynamic.MutableJsonElement RootElement { get { throw null; } }
public static Azure.Core.Dynamic.MutableJsonDocument Parse(System.BinaryData utf8Json) { throw null; }
public static Azure.Core.Dynamic.MutableJsonDocument Parse(string json) { throw null; }
public void WriteTo(System.IO.Stream stream, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { }
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial struct MutableJsonElement
{
private object _dummy;
private int _dummyPrimitive;
public bool GetBoolean() { throw null; }
public double GetDouble() { throw null; }
public float GetFloat() { throw null; }
public int GetInt32() { throw null; }
public long GetInt64() { throw null; }
public Azure.Core.Dynamic.MutableJsonElement GetProperty(string name) { throw null; }
public string? GetString() { throw null; }
public void RemoveProperty(string name) { }
public void Set(Azure.Core.Dynamic.MutableJsonElement value) { }
public void Set(bool value) { }
public void Set(double value) { }
public void Set(int value) { }
public void Set(object value) { }
public void Set(string value) { }
public void SetProperty(string name, object value) { }
public bool TryGetProperty(string name, out Azure.Core.Dynamic.MutableJsonElement value) { throw null; }
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Experimental types that might eventually move to Azure.Core</Description>
<AssemblyTitle>Microsoft Azure Client Pipeline Experimental Extensions</AssemblyTitle>
<Version>0.1.0-preview.24</Version>
<PackageTags>Microsoft Azure Client Pipeline</PackageTags>
<Nullable>enable</Nullable>
<TargetFrameworks>$(RequiredTargetFrameworks)</TargetFrameworks>
<TargetFrameworks>$(RequiredTargetFrameworks);net461;net6.0</TargetFrameworks>
<NoWarn>$(NoWarn);AZC0001;AZC0012</NoWarn>
<IncludeOperationsSharedSource>true</IncludeOperationsSharedSource>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static class BinaryDataExtensions
/// </summary>
public static dynamic ToDynamic(this BinaryData data)
{
return JsonData.Parse(data);
return new DynamicJson(MutableJsonDocument.Parse(data).RootElement);
}
}
}
12 changes: 6 additions & 6 deletions sdk/core/Azure.Core.Experimental/src/DynamicData.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Text.Json;
using System.IO;

namespace Azure.Core.Dynamic
{
Expand All @@ -14,15 +14,15 @@ namespace Azure.Core.Dynamic
public abstract class DynamicData
{
/// <summary>
/// Writes the data to the provided writer as a JSON value.
/// Writes the data to the provided stream.
/// </summary>
/// <param name="writer">The writer to which to write the document.</param>
/// <param name="stream">The stream to which to write the document.</param>
/// <param name="data">The dynamic data value to write.</param>
public static void WriteTo(Utf8JsonWriter writer, DynamicData data)
public static void WriteTo(Stream stream, DynamicData data)
{
data.WriteTo(writer);
data.WriteTo(stream);
}

internal abstract void WriteTo(Utf8JsonWriter writer);
internal abstract void WriteTo(Stream stream);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.Json;

namespace Azure.Core.Dynamic
{
public partial class DynamicJson : IDynamicMetaObjectProvider
{
private static readonly MethodInfo GetPropertyMethod = typeof(DynamicJson).GetMethod(nameof(GetProperty), BindingFlags.NonPublic | BindingFlags.Instance)!;
private static readonly MethodInfo SetMethod = typeof(DynamicJson).GetMethod(nameof(Set), BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(object) }, null)!;
private static readonly MethodInfo GetViaIndexerMethod = typeof(DynamicJson).GetMethod(nameof(GetViaIndexer), BindingFlags.NonPublic | BindingFlags.Instance)!;
private static readonly MethodInfo SetViaIndexerMethod = typeof(DynamicJson).GetMethod(nameof(SetViaIndexer), BindingFlags.NonPublic | BindingFlags.Instance)!;

/// <summary>
/// Gets a value indicating whether the current instance has a valid value of its underlying type.
/// </summary>
// TODO: Decide if this is the API we want for this. We could also expose ValueKind.
public bool HasValue => _element.ValueKind != JsonValueKind.Null;
annelo-msft marked this conversation as resolved.
Show resolved Hide resolved

private object GetProperty(string name)
{
if (name == nameof(HasValue))
{
return HasValue;
}

return new DynamicJson(_element.GetProperty(name));
}

private object GetViaIndexer(object index)
{
switch (index)
{
case string propertyName:
return GetProperty(propertyName);
case int arrayIndex:
return new DynamicJson(_element.GetIndexElement(arrayIndex));
}

throw new InvalidOperationException($"Tried to access indexer with an unsupported index type: {index}");
}

private object? Set(object value)
{
switch (value)
{
case int i:
_element.Set(i);
break;
case double d:
_element.Set(d);
break;
case string s:
_element.Set(s);
break;
case bool b:
_element.Set(b);
break;
case MutableJsonElement e:
_element.Set(e);
break;
default:
_element.Set(value);
break;

// TODO: add support for other supported types
}

// Binding machinery expects the call site signature to return an object
return null;
}

private object? SetViaIndexer(object index, object value)
{
DynamicJson element = (DynamicJson)GetViaIndexer(index);
return element.Set(value);
}

private T ConvertTo<T>()
{
// TODO: Respect user-provided serialization options

#if NET6_0_OR_GREATER
return JsonSerializer.Deserialize<T>(_element.GetJsonElement(), MutableJsonDocument.DefaultJsonSerializerOptions)!;
#else
// TODO: Could we optimize this by serializing from the byte array instead? We don't currently slice into this in WriteTo(), but could look at storing that.
return JsonSerializer.Deserialize<T>(_element.ToString(), MutableJsonDocument.DefaultJsonSerializerOptions);
#endif
}

/// <inheritdoc />
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) => new MetaObject(parameter, this);

private class MetaObject : DynamicMetaObject
{
internal MetaObject(Expression parameter, IDynamicMetaObjectProvider value) : base(parameter, BindingRestrictions.Empty, value)
{
}

public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
UnaryExpression this_ = Expression.Convert(Expression, LimitType);

Expression[] getPropertyArgs = new Expression[] { Expression.Constant(binder.Name) };
MethodCallExpression getPropertyCall = Expression.Call(this_, GetPropertyMethod, getPropertyArgs);

BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);
return new DynamicMetaObject(getPropertyCall, restrictions);
}

public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
{
UnaryExpression this_ = Expression.Convert(Expression, LimitType);

Expression[] arguments = new Expression[] { Expression.Convert(indexes[0].Expression, typeof(object)) };
MethodCallExpression getViaIndexerCall = Expression.Call(this_, GetViaIndexerMethod, arguments);

BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);
return new DynamicMetaObject(getViaIndexerCall, restrictions);
}

public override DynamicMetaObject BindConvert(ConvertBinder binder)
{
Expression targetObject = Expression.Convert(Expression, LimitType);
BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);

Expression convertCall;

//if (binder.Type == typeof(IEnumerable))
//{
// convertCall = Expression.Call(targetObject, GetDynamicEnumerableMethod);
// return new DynamicMetaObject(convertCall, restrictions);
//}

if (CastFromOperators.TryGetValue(binder.Type, out MethodInfo? castOperator))
{
convertCall = Expression.Call(castOperator, targetObject);
return new DynamicMetaObject(convertCall, restrictions);
}

convertCall = Expression.Call(targetObject, nameof(ConvertTo), new Type[] { binder.Type });
return new DynamicMetaObject(convertCall, restrictions);
}

public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
{
UnaryExpression this_ = Expression.Convert(Expression, LimitType);

Expression[] getPropertyArgs = new Expression[] { Expression.Constant(binder.Name) };
MethodCallExpression getPropertyCall = Expression.Call(this_, GetPropertyMethod, getPropertyArgs);

UnaryExpression property = Expression.Convert(getPropertyCall, typeof(DynamicJson));

Expression[] setDynamicArgs = new Expression[] { Expression.Convert(value.Expression, typeof(object)) };
MethodCallExpression setCall = Expression.Call(property, SetMethod, setDynamicArgs);

BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);
return new DynamicMetaObject(setCall, restrictions);
}

public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)
{
UnaryExpression this_ = Expression.Convert(Expression, LimitType);

Expression[] setArgs = new Expression[2] {
Expression.Convert(indexes[0].Expression, typeof(object)),
Expression.Convert(value.Expression, typeof(object))
};
MethodCallExpression setCall = Expression.Call(this_, SetViaIndexerMethod, setArgs);

BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);
return new DynamicMetaObject(setCall, restrictions);
}
}
}
}
Loading