[英]Implicit conversion from JToken in Json.NET
使用Json.NET ,我看到所有的原生类型的转换JToken
是隐式的,而是从转换JToken
是明确的。
我的动机是避免if
语句,方法调用等中的显式强制转换。例如,如果最后的if
没有抛出它会很好:
string dummyJson = @"{'ShouldDoStuff': true}";
dynamic parsed = JValue.Parse(dummyJson);
// Works:
bool explicitShouldDoStuff = parsed.ShouldDoStuff;
// Also works:
if ((bool)parsed.ShouldDoStuff)
Console.WriteLine("Hooray, there's a rosebush?");
// Throws RuntimeBinderException: Cannot implicitly convert type 'Newtonsoft.Json.Linq.JValue' to 'bool'
if (parsed.ShouldDoStuff)
Console.WriteLine("Die you gravy-sucking pigs");
有没有办法将JToken
转换JToken
机类型?
显式运算符的原因是隐式运算符会导致各种问题。 所以,不,你不能这样做,它是设计的。
但是,除了显式强制转换,您还可以获取Value
属性:
if (parsed.ShouldDoStuff.Value)
Console.WriteLine("Die you gravy-sucking pigs");
我认为这比打字更干净。
如果你不介意动手使用动态元对象,你可以编写一个包装类,可以将值转换为幕后的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!
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.