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节点, 因此它们的对象身份是被保持的. 待续!


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3