- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我最近在使用 Json.NET 将 JSON 解析为动态对象时发现空合并运算符存在问题。假设这是我的动态对象:
string json = "{ \"phones\": { \"personal\": null }, \"birthday\": null }";
dynamic d = JsonConvert.DeserializeObject(json);
如果我尝试使用 ?? d 的字段之一上的运算符,它返回 null:
string s = "";
s += (d.phones.personal ?? "default");
Console.WriteLine(s + " " + s.Length); //outputs 0
但是,如果我将动态属性分配给字符串,则它可以正常工作:
string ss = d.phones.personal;
string s = "";
s += (ss ?? "default");
Console.WriteLine(s + " " + s.Length); //outputs default 7
最后,当我输出 Console.WriteLine(d.phones.personal == null)
时,它输出 True
。
我已经在 Pastebin 上对这些问题进行了广泛的测试.
最佳答案
这是由于 Json.NET 和 ??
运算符的模糊行为。
首先,当您将 JSON 反序列化为 dynamic
对象时,实际返回的是 Linq-to-JSON 类型 JToken
的子类(例如 JObject
或JValue
) 具有 IDynamicMetaObjectProvider
的自定义实现.即
dynamic d1 = JsonConvert.DeserializeObject(json);
var d2 = JsonConvert.DeserializeObject<JObject>(json);
实际上返回的是同样的东西。所以,对于你的 JSON 字符串,如果我这样做了
var s1 = JsonConvert.DeserializeObject<JObject>(json)["phones"]["personal"];
var s2 = JsonConvert.DeserializeObject<dynamic>(json).phones.personal;
这两个表达式计算出完全相同的返回动态对象。但是返回什么对象?这让我们了解了 Json.NET 的第二个模糊行为:它不是用 null
指针表示 null 值,而是用特殊的 JValue
表示 then。与 JValue.Type
等于JTokenType.Null
.因此,如果我这样做:
WriteTypeAndValue(s1, "s1");
WriteTypeAndValue(s2, "s2");
控制台输出为:
"s1": Newtonsoft.Json.Linq.JValue: ""
"s2": Newtonsoft.Json.Linq.JValue: ""
即这些对象不为空,它们被分配了 POCO,它们的 ToString()
返回一个空字符串。
但是,当我们将该动态类型分配给字符串时会发生什么?
string tmp;
WriteTypeAndValue(tmp = s2, "tmp = s2");
打印:
"tmp = s2": System.String: null value
为什么不同?这是因为 DynamicMetaObject
由 JValue
返回解析动态类型到字符串的转换最终调用 ConvertUtils.Convert(value, CultureInfo.InvariantCulture, binder.Type)
它最终为 JTokenType.Null
值返回 null
,这与显式转换为字符串所执行的逻辑相同,避免了对 dynamic
的所有使用:
WriteTypeAndValue((string)JsonConvert.DeserializeObject<JObject>(json)["phones"]["personal"], "Linq-to-JSON with cast");
// Prints "Linq-to-JSON with cast": System.String: null value
WriteTypeAndValue(JsonConvert.DeserializeObject<JObject>(json)["phones"]["personal"], "Linq-to-JSON without cast");
// Prints "Linq-to-JSON without cast": Newtonsoft.Json.Linq.JValue: ""
现在,进入实际问题。作为husterk注意到 ?? operator当两个操作数之一是 dynamic
时返回 dynamic
,所以 d.phones.personal ?? “default”
不会尝试执行类型转换,因此返回的是 JValue
:
dynamic d = JsonConvert.DeserializeObject<dynamic>(json);
WriteTypeAndValue((d.phones.personal ?? "default"), "d.phones.personal ?? \"default\"");
// Prints "(d.phones.personal ?? "default")": Newtonsoft.Json.Linq.JValue: ""
但是如果我们通过将动态返回分配给字符串来调用 Json.NET 到字符串的类型转换,那么转换器将启动并返回一个实际的空指针在合并运算符完成其工作并返回一个非-null JValue
:
string tmp;
WriteTypeAndValue(tmp = (d.phones.personal ?? "default"), "tmp = (d.phones.personal ?? \"default\")");
// Prints "tmp = (d.phones.personal ?? "default")": System.String: null value
这解释了您所看到的差异。
要避免此行为,请在应用合并运算符之前强制从动态转换为字符串:
s += ((string)d.phones.personal ?? "default");
最后,将类型和值写入控制台的辅助方法:
public static void WriteTypeAndValue<T>(T value, string prefix = null)
{
prefix = string.IsNullOrEmpty(prefix) ? null : "\""+prefix+"\": ";
Type type;
try
{
type = value.GetType();
}
catch (NullReferenceException)
{
Console.WriteLine(string.Format("{0} {1}: null value", prefix, typeof(T).FullName));
return;
}
Console.WriteLine(string.Format("{0} {1}: \"{2}\"", prefix, type.FullName, value));
}
(顺便说一句,空类型 JValue
的存在解释了表达式 (object)(JValue)(string)null == (object)(JValue)null
可能评估为 false
)。
关于c# - Null 合并运算符为动态对象的属性返回 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29051663/
最近开始学习oracle和sql。 在学习的过程中,我遇到了几个问题,我的 friend 在接受采访时被问到这些问题。 SELECT * FROM Employees WHERE NULL IS N
这个问题在这里已经有了答案: Can we subtract NULL pointers? (4 个回答) 关闭 2 个月前。 是否定义了NULL - NULL? (char *)NULL - (ch
是否有推荐的方法(根据 .net Framework 指南)检查 null,例如: if (value == null) {//code1} else {//code2} 或 if (value !=
我正在尝试将值插入数据库,但出现这样的错误任何人都可以告诉我为什么该值为空,如下所示: An exception occurred while executing 'INSERT INTO perso
这个问题在这里已经有了答案: String concatenation with a null seems to nullify the entire string - is that desire
您好,我正在 Android 联系人搜索模块中工作。我正在查询下方运行。 cur = context.getContentResolver().query(ContactsContract.Data.
下面的 SQL 表定义说明了从我的 MYSQL 数据库创建表的语句之一,该数据库是由我公司的前开发人员开发的。 DROP TABLE IF EXISTS `classifieds`.`category
我主要有应用程序开发背景。在编程语言中 variable == null或 variable != null有效。 当涉及到 SQL 时,以下查询不会给出任何语法错误,但也不会返回正确的结果。 sel
我在尝试检查某些元素是否为 NULL 时遇到段错误或不。任何人都可以帮忙吗? void addEdge(int i, int j) { if (i >= 0 && j > 0)
在 SQL 服务器中考虑到以下事实:Col1 和 Col2 包含数值和 NULL 值 SELECT COALESCE(Col1,Col2) 返回一个错误:“COALESCE 的至少一个参数必须是一个不
在 SQL 服务器中考虑到以下事实:Col1 和 Col2 包含数值和 NULL 值 SELECT COALESCE(Col1,Col2) 返回一个错误:“COALESCE 的至少一个参数必须是一个不
下面查询的关系代数表达式是什么?我找不到“Is Null”的表达式。 SELECT reader.name FROM reader LEFT JOIN book_borrow ON reader.ca
我正在尝试使用三元运算符来检查值是否为 null 并返回一个表达式或另一个。将此合并到 LINQ 表达式时,我遇到的是 LINQ 表达式的 Transact-SQL 转换试图执行“column = n
我在给定的代码中看到了以下行: select(0, (fd_set *) NULL, (fd_set *) NULL, (fd_set *) NULL, &timeout); http://linux
var re = /null/g; re.test('null null'); //> true re.test('null null'); //> true re.test('null null')
这个问题在这里已经有了答案: 关闭 13 年前。 我今天避开了一场关于数据库中空值的激烈辩论。 我的观点是 null 是未指定值的极好指示符。团队中有意见的其他每个人都认为零和空字符串是可行的方法。
由于此错误,我无法在模拟器中运行我的应用: Error:null value in entry: streamOutputFolder=null 或 gradle - Error:null value
我正在尝试在 Android 应用程序中创建电影数据库,但它返回错误。知道这意味着什么吗? public Cursor returnData() { return db.query(TABLE
我一直在检查浏览器中的日期函数以及运行时间 new Date (null, null, null); 在开发工具控制台中,它给出了有效的日期 Chrome v 61 回归 Sun Dec 31 189
为什么 NA==NULL 会导致 logical (0) 而不是 FALSE? 为什么 NULL==NULL 会导致 logical(0) 而不是 TRUE? 最佳答案 NULL 是一个“零长度”对象
我是一名优秀的程序员,十分优秀!