LINQ学习笔记:string类型的Value属性
与Value打交道
XElement与XAttribute的都有一个string类型的Value属性. 如果一个元素包含有一个单一的XText子节点, 那么XElement的Value属性就相当于访问此节点内容的快捷方式. 对于XAttribute, Value属性就是指attribute的值.
尽管存储体不一样, X-DOM还是提供了一致的操作方式用于元素和attribute的值.
设置Values
有两中方式用于分配一个值: 调用SetValue或者赋值给Value属性. 相比之下SetValue更加灵活一点, 因为它不仅仅接受string类型, 也可以接受其他的简单类型:
1: var e = new XElement ("date", DateTime.Now);
2: e.SetValue (DateTime.Now.AddDays(1));
3: Console.Write (e.Value);
我们可以简单的设置值到元素的Value属性, 但这意味着你需要手动将DateTime转换成string类型. 这将会更加复杂–因为它需要使用XmlConvert来转换成为一个XML兼容的结果.
获取Values
为了将一个Value值转换成为其基础类型, 我们可以简单转换XElement或者XAttribute到我们期望的类型. 这听起来似乎是不能工作的, 但实际上是它完全没有任何问题. 例如:
1: XElement e = new XElement ("now", DateTime.Now);
2: DateTime dt = (DateTime) e;
3:
4: XAttribute a = new XAttribute ("resolution", 1.234);
5: double res = (double) a;
一个元素或者attribute并不会天然的存储DateTime或者数字–他们总是将其保存为文本, 然后转换为真正需要的. 它也没有记住其原始类型, 因为你必须要将其转换为正确的类型以避免出现运行时错误.要让你的代码更加健壮, 可以使用try / catch块, 捕获一个FormatException.
XElement与XAttribute的显式转换可以将其转换为以下的类型:
- 所有的数值类型
- string, bool, DateTime, DateTimeOffset, TimeSpan与Guid
- 上述所有类型的Nullable<>版本
如果请求的名称不存在的时候, 转换到nullable类型在对于连带着Element和Attribute的方法是非常有用的, 其转换应该可以顺利完成. 例如, 如果x没有timeout元素, 第一行将会引起一个运行时错误, 而第二行则不会:
1: int timeout = (int) x.Element ("timeout"); // 错误
2: int? timeout = (int?) x.Element ("timeout"); // OK
我们可以使用??操作符来去除最后结果中的nullable类型. 以下的代码在resolution属性不存在的情况下将会返回1.0
1: double resolution =
2: (double?) x.Attribute ("resolution") ?? 1.0;
不过, 如果element或者attribute存在并且包含一个空值(或者不正确的格式), 转换到nullable类型并不会让你就远离麻烦. 上述情况, 你将会得到一个FormatException.
我们也可以在LINQ查询中使用类型转换. 例如以下的查询返回”John”:
1: var data = XElement.Parse (
2: @"<data>
3: <customer id='1' name='Mary' credit='100' />
4: <customer id='2' name='John' credit='150' />
5: <customer id='3' name='Anne' />
6: </data>");
7:
8: IEnumerable<string> query =
9: from cust in data.Elements( )
10: where (int?) cust.Attribute ("credit") > 100
11: select cust.Attribute ("name").Value;
转换到一个nullable的int类型避免了NullReferenceException的产生(Anne没有credit属性). 另一种解决方案是给加一个断言到where从句中.
1: where cust.Attributes ("credit").Any()
2: &&(int) cust.Attribute...
同样的原则也可以应用于查询元素的值.
值与混合的内容节点
由于有了Value属性, 你可能会好奇什么时候你才需要直接和XText节点打交道呢? 答案是: 当你拥有混合的内容的时候. 例如:
1: <summary>
2: An XAttribute is <bold>not</bold> an XNode
3: </summary>
一个简单的Value属性是不能够获取summary的全部内容的. summary元素包含了3个孩子:一个XText节点, 紧接着一个XElement, 然后再一个XText节点. 我们来看它是如何被构造的:
1: XElement summary = new XElement ("summary",
2: new XText ("An XAttribute is "),
3: new XElement ("bold", "not"),
4: new XText (" an XNode")
5: );
有趣的是, 你依然还是可以查询summary的Value值, 这并不会引起任何的异常. 相反, 我们获得了每一个子节点的Value值的连接字符.
An XAttribute is not an XNode
重设summary的Value值也是合法的, 它将使用一个单一的XText节点替换前面提到的所子节点.
自动XText连接
当你增加简单内容到一个XElement的时候, X-DOM将其添加到已存在的XText子节点中而不是去创建一个新的节点. 在下面的例子中, e1和e2最后形成了一个单一的XText元素, 其值是”HelloWorld”.
1: var e1 = new XElement ("test", "Hello");
2: e1.Add ("World");
3:
4: var e2 = new XElement ("test", "Hello", "World");
如果你指定要创建XText节点, 最终将会形成多个孩子节点:
1: var e = new XElement ("test",
2: new XText ("Hello"),
3: new XText ("World"));
4: Console.WriteLine (e.Value); // HelloWorld
5: Console.WriteLine (e.Nodes( ).Count( )); // 2
XElement不会自动连接两个XText节点, 因此它们的对象身份是被保持的. 待续!