Implicit conversion from JToken to Json.NET

Using Json.NET , I see that all conversions of native types to JToken are implicit, but conversions from JToken are explicit.

My motivation is to avoid explicit drops in operators if, method calls, etc. For example, it would be nice if the latter ifdid not choose:

string dummyJson = @"{'ShouldDoStuff': true}";
dynamic parsed = JValue.Parse(dummyJson);

// Works:
bool explicitShouldDoStuff = parsed.ShouldDoStuff; 

// Also works:
if ((bool)parsed.ShouldDoStuff)
    Console.WriteLine("Hooray, there a rosebush?");

// Throws RuntimeBinderException: Cannot implicitly convert type 'Newtonsoft.Json.Linq.JValue' to 'bool'
if (parsed.ShouldDoStuff)   
    Console.WriteLine("Die you gravy-sucking pigs");

Is there a way to make conversions from JTokento native types implicit too?

+4
source share
2 answers

, . , , , .

, , Value:

if (parsed.ShouldDoStuff.Value)
    Console.WriteLine("Die you gravy-sucking pigs");

, , .

+4

, , -, bool .

, :

public class JTokenWrapper : DynamicObject
{
    public JTokenWrapper(JToken token)
    {
        if (token == null) throw new ArgumentNullException("token");
        this.Token = token;
    }
    public JToken Token { get; private set; }

    public override DynamicMetaObject GetMetaObject(Expression parameter)
    {
        return new JValueUnwrapperMetaObject(parameter, Token);
    }

    class JValueUnwrapperMetaObject : ProjectedDynamicMetaObjectWrapper<JToken>
    {
        public JValueUnwrapperMetaObject(Expression expression, JToken token)
            : base(expression, ExpressionSelector, token)
        {
        }

        private static Expression ExpressionSelector(Expression expression)
        {
            return LinqExpression.Property(
                LinqExpression.Convert(expression, typeof(JTokenWrapper)),
                "Token"
            );
        }

        public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
        {
            return UnwrappedValue(base.BindGetMember(binder));
        }

        public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
        {
            return UnwrappedValue(base.BindGetIndex(binder, indexes));
        }

        private DynamicMetaObject UnwrappedValue(DynamicMetaObject getter)
        {
            var expr = GenerateUnwrapperExpression(getter.Expression);
            return new DynamicMetaObject(expr, getter.Restrictions, getter.Value);
        }

        private static readonly Dictionary<JTokenType, Func<Expression, Expression>> UnwrappedTypes = new Dictionary<JTokenType, Func<Expression, Expression>>
        {
            { JTokenType.Boolean,   UnwrapBoolean   },
            { JTokenType.String,    UnwrapString    },
            { JTokenType.Integer,   UnwrapInteger   },
        };

        private static Expression ExplicitConvert(Expression token, Type type)
        {
            return LinqExpression.Convert(
                token,
                type,
                typeof(JToken).GetMethods().Where(m => m.Name == "op_Explicit").Single(m => m.ReturnType == type)
            );
        }

        private static Expression UnwrapBoolean(Expression token)
        {
            return ExplicitConvert(token, typeof(bool));
        }

        private static Expression UnwrapString(Expression token)
        {
            return ExplicitConvert(token, typeof(string));
        }

        private static Expression UnwrapInteger(Expression token)
        {
            // TODO: figure out the appropriate type
            return token;
        }

        private Expression GenerateUnwrapperExpression(Expression value)
        {
            var token = LinqExpression.Variable(typeof(JToken));
            var returnTarget = LinqExpression.Label(typeof(object));
            return LinqExpression.Block(
                typeof(object),
                new ParameterExpression[] { token },
                LinqExpression.Assign(token, LinqExpression.Convert(value, typeof(JToken))),
                LinqExpression.Switch(
                    LinqExpression.Property(token, "Type"),
                    UnwrappedTypes.Select(x =>
                        LinqExpression.SwitchCase(
                            LinqExpression.Return(returnTarget,
                                LinqExpression.Convert(
                                    x.Value(token),
                                    typeof(object)
                                )
                            ),
                            LinqExpression.Constant(x.Key)
                        )
                    ).ToArray()
                ),
                LinqExpression.Label(
                    returnTarget,
                    LinqExpression.New(
                        typeof(JTokenWrapper).GetConstructors().Single(),
                        LinqExpression.Convert(value, typeof(JToken))
                    )
                )
            );
        }
    }
}

:

public abstract class DynamicMetaObjectWrapper : DynamicMetaObject
{
    public DynamicMetaObjectWrapper(Expression expression, DynamicMetaObject wrappedMetaObject)
        : base(expression, wrappedMetaObject.Restrictions, wrappedMetaObject.Value)
    {
        this.MetaObject = wrappedMetaObject;
    }
    public DynamicMetaObjectWrapper(DynamicMetaObject wrappedMetaObject)
        : this(wrappedMetaObject.Expression, wrappedMetaObject)
    {
    }
    public DynamicMetaObject MetaObject { get; private set; }

    public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
    {
        return MetaObject.BindBinaryOperation(binder, arg);
    }

    public override DynamicMetaObject BindConvert(ConvertBinder binder)
    {
        return MetaObject.BindConvert(binder);
    }
    public override DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args)
    {
        return MetaObject.BindCreateInstance(binder, args);
    }

    public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes)
    {
        return MetaObject.BindDeleteIndex(binder, indexes);
    }

    public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
    {
        return MetaObject.BindDeleteMember(binder);
    }

    public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
    {
        return MetaObject.BindGetIndex(binder, indexes);
    }

    public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
    {
        return MetaObject.BindGetMember(binder);
    }

    public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)
    {
        return MetaObject.BindInvoke(binder, args);
    }

    public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
    {
        return MetaObject.BindInvokeMember(binder, args);
    }

    public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)
    {
        return MetaObject.BindSetIndex(binder, indexes, value);
    }

    public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
    {
        return MetaObject.BindSetMember(binder, value);
    }

    public override DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder)
    {
        return MetaObject.BindUnaryOperation(binder);
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return MetaObject.GetDynamicMemberNames();
    }
}
public abstract class ProjectedDynamicMetaObjectWrapper<TProvider> : DynamicMetaObjectWrapper where TProvider : class, IDynamicMetaObjectProvider
{
    public ProjectedDynamicMetaObjectWrapper(Expression expression, Func<Expression, Expression> expressionSelector, TProvider provider)
        : base(expression, provider.GetMetaObject(expressionSelector(expression)))
    {
    }
}

, , :

var jsonStr = @"{""ShouldDoStuff"":true}";
var value = JValue.Parse(jsonStr);
dynamic wrapped = new JTokenWrapper(value);

if (wrapped.ShouldDoStuff)
{
    // success!
}
+1

Source: https://habr.com/ru/post/1524031/


All Articles