Hello World
Spiga

二十行C#代码打造Ruby Markup Builder

2009-10-27 00:47 by 老赵, 19680 visits

从.NET诞生之日起就有了XML类库,但是从使用上来说非常不方便。例如我们需要构造一个XML文档时,使用DOM API就要这样搞:

var xmlDoc = new XmlDocument();
var rootEle = xmlDoc.CreateElement("persons");
xmlDoc.AppendChild(rootEle);

var person1 = xmlDoc.CreateElement("person");
person1.InnerText = "Tom";
var person1Age = xmlDoc.CreateAttribute("age");
person1Age.Value = "10";
person1.Attributes.Append(person1Age);
rootEle.AppendChild(person1);

var person2 = xmlDoc.CreateElement("person");
person2.InnerText = "Jerry";
var person2Age = xmlDoc.CreateAttribute("age");
person2Age.Value = "8";
person2.Attributes.Append(person2Age);
rootEle.AppendChild(person2);

别看这么多行代码,但实际上它只构造了这么简单的一个XML:

<persons>
  <person age="10">Tom</person>
  <person age="8">Jerry</person>
</persons>

我承认,DOM API的确非常严谨(如XmlDocument和XmlElement的归属关系),非常符合定义,也非常的面向对象,但是这易用性也实在太差了。记得在03还是04年的时候,我为在为项目做一个编辑XML文档的WinForm应用程序,当时也不像现在那么容易想到“偷懒”的法门,而VS 2003也不像VS 2005/2008那么好用,因此可谓做的劳心费神。这个情况在.NET 2.0中也没有得到改变,直到有一天,LINQ to XML随.NET 3.5横空出世,于是乎XML的生活一下子变得美好了很多。例如上面的功能只需寥寥数行便可以实现:

var xmlDoc = new XElement("persons",
    new XElement("person",
        "Tom",
        new XAttribute("age", 10)),
    new XElement("person",
        "Jerry",
        new XAttribute("age", 8))); 

虽然LINQ to XML一直是所谓C# 3.0中LINQ特性的一部分,与LINQ to SQL,LINQ to Object及LINQ to……某个别的并列,但我始终认为LINQ to XML实则还是LINQ to Object的一种特殊形式,只是它用于操作XML而已。它的一切都是System.Xml.Linq命名空间下相关类库(如XElement)在起作用,不关LINQ什么事情。XElement等相关类型大大简化了我们的开发,与DOM API相比,无论是XML的构造还是读取都容易了许多。不过俗话说得好:“不怕不识货,就怕货比货”,这样的API与Ruby Markup Builder相比还是有明显差距。请看:

builder = Builder::XmlMarkup.new
xml = builder.persons { |b|
    b.person("Tom", :age => "10")
    b.person("Jerry", :age => "8")
}

请看上面这段代码,它自然没有使用Ruby语言的标准着色方式。我着色的目的是体现这个构造方式中的“噪音”——也就是与XML内容无关的部分。从中可以发现,Ruby不愧是一种噪音较少的语言,如果您尝试使用这个方式来观察C#中LINQ to XML的做法,就会发现两者之间的确有明显的差距。当然,如果使用VB.NET的XML Literal可能噪音也很少,但是在我看来,XML Literal在XML构造方面的表现有些罗嗦,例如它需要开发人员同时提供元素的开始标签和闭合标签,可能在IDE的帮助下此类代码输入较为简单,但是代码还是略显冗余。

但是我们这些可怜的C#程序员难道只有在一边眼馋的份吗?不见得,我们也可以来“享受”一把:

dynamic b = new XmlMarkupBuilder();
XElement xml =
    b.persons(
        b.person("Tom", age: 10),
        b.person("Jerry", age: 8));

哇,这是什么,怎么代码那么简单。很明显,从dynamic关键字上可以看出,这是C# 4.0中新增的功能。您可能会想“原来.NET 4.0对XML又有增强了”……其实并非如此,这是我们自己扩展的功能。不过这应该算是更好的消息,因为这说明我们已经有能力自行扩展,自行设计这样的API了——这可是“渔”,比“鱼”可要值钱多了。而实现这样的功能也只需要短短二十几行C#代码:

public class XmlMarkupBuilder : DynamicObject
{
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        XElement xml = new XElement(binder.Name);

        var attrCount = binder.CallInfo.ArgumentNames.Count;
        var elementCount = args.Length - attrCount;

        for (int i = 0; i < elementCount; i++)
        {
            xml.Add(args[i]);
        }

        for (var i = 0; i < attrCount; i++)
        {
            var attrName = binder.CallInfo.ArgumentNames[i];
            if (attrName[0] == '@') attrName = attrName.Substring(1);

            xml.Add(new XAttribute(attrName, args[i + elementCount]));
        }

        result = xml;
        return true;
    }
}

DynamicObject是个特殊的对象,简单地说它的行为可以被“扩展”——是如动态语言般真正的扩展,而非静态的多态。当我们使用dynamic修饰变量后,在它之上的方法调用会由编译器和DLR配合出不一样的行为。例如,我们在调用一个方法的时候,DLR会先检查这个动态对象上是否存在符合这个签名的方法,存在则最好,否则便会调用TryInvokeMember来“执行”一个动态方法,而它的参数便是此次调用的全部信息。这样的做法被称为“Method Missing”操作,事实上Ruby Markup Builder也是使用Ruby对象中的这个特性来实现“调用什么方法,便生成什么元素”的功能。此外,我们还可以这么用:

var persons = new [] { new Person("Tom", 10), new Person("Jerry", 8) };
XElement xml2 = 
    b.persons(
        from p in persons
        select b.person(p.Name, age: p.Age));

XmlMarkupBuilder对LINQ的直接支持得益于XElement无与伦比的“包容性”(因此我认为LINQ to XML其实只是LINQ to Object + 类库)。至于age: 10这样的代码,其实是使用了C# 4.0的新特性:命名参数(Named Parameters)——C#还真把什么都为我们准备好了。

即便是大部分DynamicObject的示例都喜欢拿XML操作开涮(但还是没有出现我这篇的用法,所以我还是“原创”),但事实上这个功能可发挥的余地非常之大。例如,陈猫同学提到他想用这个功能来简化Silverlight中的JSON操作,刚“喜得贵女”的Phil Haack同学在上个月也提到一个设想,它在ASP.NET MVC中使用dynamic关键字来修饰View的Model,这样在访问Model的属性时变可附加一些约定好的操作。例如,Model.Content表示读取Content属性的内容,而Model._Content则表示在读取Content之后自动进行HTML编码。这无疑简化了我们的开发——当然,强类型的各种优势就不复存在了。

而这个功能对我的意义在于,我又找到了一种设计API的方式,它可以使类库变得简单好用——就好比上面的XmlMarkupBuilder一样。虽然,这个示例的功能非常简单,但是这也足以证明C# 4.0中的dynamic特性并不仅仅是“方便Interop操作”或是“简化反射”这么简单,如果我们可以发挥想象能力,加以充分利用同时又不滥用,我们的程序开发生活就会变得越来越美好。

最后……我还是承认了吧,这篇文章其实是标题党,真正Ruby Markup Builder功能非常强大而复杂,我们的XmlMarkupBuilder类只能算是冰山一角而已。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

77 条回复

  1. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 00:56:00

    Linq to XML 还是VB比较NB

    dynamic b = new XmlMarkupBuilder();
    XElement xml =
        b.persons(
            b.person("Tom", age: 10),
            b.person("Jerry", age: 8));
    



    相当于

    dim xml=<persons>
      <person age="10">Tom</person>
      <person age="8">Jerry</person>
    </persons>
    
    

  2. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 01:08:00

    我一直希望c#搞成vb那样的支持
    就算2010自称一视同仁 也还是作不到


           Dim xml = <persons>
                          <person age="10">Tom</person>
                          <person age="8">Jerry</person>
                      </persons>
    
            xml.<person>.First().Add(
                <a>
                    haha we added here
                </a>
                                    )
    
            Console.Write(xml.ToString)
            Console.ReadKey()
    
    

    一点都看不到xml以外的累赘


    话说开始闭合也不必要
    xml.<person>.First().Add(<a/>)
    哈哈

  3. javascript[未注册用户]
    *.*.*.*
    链接

    javascript[未注册用户] 2009-10-27 01:08:00

    @韦恩卑鄙
    嗯,spidermonkey 也支持这种语法,比较方便。VB历来有好些特性比C#牛,像延迟绑定,没有.net 4.0的环境,是不错的代替,只是我很讨厌没有{}的语言,典型强迫症哈。

  4. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 01:11:00

    睡觉了 明天聊 呵呵

  5. javascript[未注册用户]
    *.*.*.*
    链接

    javascript[未注册用户] 2009-10-27 01:45:00

    不知道VB是不是仅支持完整的xml:
    Dim xml = <persons>
    <person age="10">Tom</person>
    <person age="8">Jerry</person>
    </persons>
    如果这样的话,那无非是鸡肋。没比new XmlDocument().LoadXml(xmlText)好多少。要的是构建时噪音代码少,像:
    var persons = new [] { new Person("Tom", 10), new Person("Jerry", 8) };
    XElement xml2 =
    b.persons(
    from p in persons
    select b.person(p.Name, age: p.Age));

  6. winter-cn
    *.*.*.*
    链接

    winter-cn 2009-10-27 02:03:00

    dynamic 果然够狠啊 直接顺手成员函数调用也给动态了

  7. vczh[未注册用户]
    *.*.*.*
    链接

    vczh[未注册用户] 2009-10-27 02:33:00

    DynamicObject永远是实现动态语言的标尺啊,而且实现起来非常有意思……

  8. vczh[未注册用户]
    *.*.*.*
    链接

    vczh[未注册用户] 2009-10-27 02:41:00

    @javascript
    非完整(譬如说你要用一个循环才能构造出所有element)的VB XML写起来就跟asp差不多,你可以看msdn。非常漂亮

  9. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 06:54:00

    我是搬运工人
    http://msdn.microsoft.com/en-us/library/bb384629.aspx


    
    Public Class XmlSamples
    
      Public Sub Main()
        ' Initialize the objects. 
    
        Dim phoneNumbers2 As Phone() = { _
            New Phone("home", "206-555-0144"), _
            New Phone("work", "425-555-0145")}
    
        ' Convert the data contained in phoneNumbers2 to XML. 
    
        Dim contact2 = _
            <contact>
              <name>Patrick Hines</name>
              <%= From p In phoneNumbers2 _
                Select <phone type=<%= p.Type %>><%= p.Number %></phone> _
              %>
            </contact>
    
        Console.WriteLine(contact2)
      End Sub
    
    End Class
    
    Class Phone
      Public Type As String
      Public Number As String
      Public Sub New(ByVal t As String, ByVal n As String)
        Type = t
        Number = n
      End Sub
    End Class
    
    

  10. Allen Lee
    *.*.*.*
    链接

    Allen Lee 2009-10-27 08:12:00

    这个..哈..Ruby的XML Builder也被你盯上了..

  11. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 08:52:00

    javascript:
    不知道VB是不是仅支持完整的xml:



    VB支持在XML Literal中嵌入任意表达式。还支持XML Expression和XML namespace

    C#再怎么改造,也不可能达到VB在XML处理上的优越程度。

    老赵赶紧学VB吧

  12. 横刀天笑
    *.*.*.*
    链接

    横刀天笑 2009-10-27 08:55:00

    嗯,这是Ruby的动态性,加上Missing Method特性和Iterator做到的。
    Rails里还有一种模板引擎也是基于这种方式。
    终于在C#里也有这种~~~

  13. 老赵
    admin
    链接

    老赵 2009-10-27 09:03:00

    @装配脑袋
    我不是XML处理专业户,哈哈。
    如果我要处理很多XML的话,我可能会用IronRuby,因为只要一个小文件放脚本就可以了……

  14. 老赵
    admin
    链接

    老赵 2009-10-27 09:06:00

    @韦恩卑鄙
    javascript兄的意思是,构造起来“不要用那么完整的XML”吧。
    XML Literal在构造时非要把开始标签和闭合标签都填上,有些累赘。
    我文章里的意思也是,XML Literal读取XML容易,构造XML有些麻烦。
    当然,VB的XML Literal还是很直观的。

  15. gjcn
    *.*.*.*
    链接

    gjcn 2009-10-27 09:07:00

    大哥现在是一天一篇啊。

  16. Jeffrey Chan
    *.*.*.*
    链接

    Jeffrey Chan 2009-10-27 09:08:00

    val xml=<persons>
    <person age="10">Tom</person>
    <person age="8">Jerry</person>
    </persons>
    看来scala的构造跟vb差不多吧.都很直观的.

  17. 老赵
    admin
    链接

    老赵 2009-10-27 09:09:00

    @gjcn
    我前一段时间都是一天两篇的。

  18. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 09:10:00

    并不需要把闭合标签填全呀。VB引入了SGML隐式标签闭合</>。 另外这一种你怎么处理呢?

    Dim e = "MyElement"
    Dim f = "myAttribute"
    Dim x = <<%= e %> <%= f %>="1">动态元素名</>

    也许要到下一个版本,.NET语言(或者说可能仅VB)才支持用变量来表示动态调用的方法名和命名参数名。

  19. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 09:16:00

    很多情况下,处理XML文件并不是直接把他手写出来,而是直接存在目标XML的框架。用VB处理,可以直接Copy-Paste进来,而且还有IDE的高亮和折叠显示,甚至有智能感知的支持。

    所以说别浪费了人家心血哦,赶紧用吧^_^

  20. 老赵
    admin
    链接

    老赵 2009-10-27 09:16:00

    @装配脑袋
    哇,原来如此。
    如果要通过变量动态确定标签名,只能使用一个额外的方法了,呵呵。

  21. CoolCode
    *.*.*.*
    链接

    CoolCode 2009-10-27 09:17:00

    @韦恩卑鄙
    VB在好像不支持匿名方法,如ForEach(...)
    匿名函数倒支持的可以 : ForEach( Function(c) c... ) 这样就必须要返回值,不知道有更好的写法不

  22. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 09:19:00

    CoolCode:
    @韦恩卑鄙
    VB在好像不支持匿名方法,如ForEach(...)
    匿名函数倒支持的可以 : ForEach( Function(c) c... ) 这样就必须要返回值,不知道有更好的写法不



    VB2010已经支持。但是我觉得仅ForEach这个例子并不比真的ForEach好多少……

    list1.ForEach(Sub(a) Console.WriteLine(a))

  23. 疯流成性
    *.*.*.*
    链接

    疯流成性 2009-10-27 09:35:00

    没看懂这个方法。

  24. CoolCode
    *.*.*.*
    链接

    CoolCode 2009-10-27 09:36:00

    @装配脑袋
    谢谢

  25. CoolCode
    *.*.*.*
    链接

    CoolCode 2009-10-27 09:44:00

    对于dynamic,我的想法是对于没有智能提示的情况下,以及那些容易打错别字的程序员来说,dynamic是个“危险”的操作。
    如老赵文章的例子:

    XElement xml =
        b.persons(
            b.person("Tom", age: 10),
            b.person("Jerry", age: 8));
    

    就算写成这样也不会有错
    XElement xml =
        b.persons(
            b.person("Tom", age: 10),
            b.preson("Jerry", age: 8));
    

    (注:第二个person特意写错了)
    然后等到其他program用到这个xml文档时才发现错误,那就糟了。

  26. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 09:47:00

    VB对XML的支持不限于处理XML吧。其实是一个非常强大的特性,尤其是VB支持的混写模式,甚至于可以在XML内部使用ASP.NET语法,代码和XML之间无界限。

    这样的特性如果只是用来处理XML就太暴殄天物了,显然XML是一种非常良好的数据储存格式,很多时候比关系型数据更好用。

    不过VB如果能将XML Literal直接编译成强类型的对象,就更爽了。。

  27. 老赵
    admin
    链接

    老赵 2009-10-27 09:49:00

    @CoolCode
    用字符串一样会拼错啊,动态语言更会有这种问题,呵呵。
    所以,比如用单元测试来保护一下还是很重要的。

  28. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 09:50:00

    老赵的这个例子的确有点标题党,因为这种东西不用dynamic同样可以处理的很好,用匿名对象就是。

    new XElement(
      new ElementBuilder( "Tom", new { Age = 10 } )
      new ElementBuilder( "Jerry", new { Age = 8 } )
    );
    

  29. CoolCode
    *.*.*.*
    链接

    CoolCode 2009-10-27 09:50:00

    所以我的想法是:VS是否应该能够根据 程序员写的第一个person后,当他写第二个person时,VS来为这个动态对象给出person的智能提示呢?

  30. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 09:51:00

    CoolCode:所以我的想法是:VS是否应该能够根据 程序员写的第一个person后,当他写第二个person时,VS来为这个动态对象给出person的智能提示呢?




    个人认为IDE不应有这种猜测,否则更容易混乱。

  31. 老赵
    admin
    链接

    老赵 2009-10-27 09:51:00

    @Ivony...
    VB的XML Literal是语言层面的支持,dynamic这个是语言和框架/类库相配合的层面。
    如何用好dynamic这个做法,又要发挥程序员的想象能力了。

  32. 老赵
    admin
    链接

    老赵 2009-10-27 09:54:00

    Ivony...:
    老赵的这个例子的确有点标题党,因为这种东西不用dynamic同样可以处理的很好,用匿名对象就是。

    new XElement(
      new ElementBuilder( "Tom", new { Age = 10 } )
      new ElementBuilder( "Jerry", new { Age = 8 } )
    );
    


    呵呵,是会方便一些,在没有dynamic的时候就是类似这种辅助方法,但是它和Ruby Markup Builder的差距也是很明显的,不是吗?
    总之还是说,如果把XElement,ElementBuilder这种东西都写进代码里,就表示了很多xml以外的信息——也没有看到什么特别的优势。

  33. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 09:55:00

    Ivony...:
    VB对XML的支持不限于处理XML吧。其实是一个非常强大的特性,尤其是VB支持的混写模式,甚至于可以在XML内部使用ASP.NET语法,代码和XML之间无界限。

    这样的特性如果只是用来处理XML就太暴殄天物了,显然XML是一种非常良好的数据储存格式,很多时候比关系型数据更好用。

    不过VB如果能将XML Literal直接编译成强类型的对象,就更爽了。。




    我就用这个XML Literal生成代码。我们项目目前有10000多行代码是我用一个600行VB程序生成的。。

  34. 老赵
    admin
    链接

    老赵 2009-10-27 10:02:00

    @装配脑袋
    写个文章介绍一下吧,私下也行。

  35. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 10:09:00

    @Jeffrey Zhao
    很简单啦,只要你觉得能这么用的话

    Function CreateValueTypeProperty(ByVal propTypeName As String, ByVal propName As String) As XElement
        Return <code>
            [System.Runtime.Serialization.DataMember]
            public <%= propTypeName & " " %><%= propName %> { get; set; }
    </code>
    End Function
    

  36. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 10:13:00

    我没看错的话,这是在生成C#的代码吧。。。。。

  37. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 10:15:00

    Ivony...:我没看错的话,这是在生成C#的代码吧。。。。。




    你以为呢……生成什么都可以啊^_^

  38. JimLiu
    *.*.*.*
    链接

    JimLiu 2009-10-27 10:19:00

    嗷呜。。。我还以为C# 3.0就可以用,谁知的要用到dynamic(话说我看到文章前一半的时候还满怀憧憬)。呃呃。。。。不过现在的XElement也还算好用了,比起Ruby是不如,不过我觉得也就是多敲代码的事情了,思想无差异,打字是体力活,当然是能省就省。

  39. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 10:27:00

    现在能想到的最简的C#等价方案:

          builder.Template(
          @"
          [System.Runtime.Serialization.DataMember] 
          public {propTypeName} {propName} { get; set; }"
          ).Bind( propTypeName: "string", propName: "A");
    

  40. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 10:30:00

    Jeffrey Zhao:
    @装配脑袋
    写个文章介绍一下吧,私下也行。


    严禁交头接耳

  41. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 10:30:00

    @Ivony...
    我还有里面用到Linq语句的呢……,还有双层嵌套的呢。。

  42. 老赵
    admin
    链接

    老赵 2009-10-27 10:30:00

    装配脑袋:

    Ivony...:我没看错的话,这是在生成C#的代码吧。。。。。


    你以为呢……生成什么都可以啊^_^


    那个谁说的,如果你不喜欢其他语言,就用LISP生成他们。

  43. 老赵
    admin
    链接

    老赵 2009-10-27 10:30:00

    @Ivony...
    其实要我的话,就直接上T4 Tempalte了吧,就是纯粹asp.net的写法,还不需要web server驱动(当然asp.net也一定可以不需要,只是不知道咋搞)。

  44. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 10:35:00

    Jeffrey Zhao:
    @Ivony...
    其实要我的话,就直接上T4 Tempalte了吧,就是纯粹asp.net的写法,只不过不需要web server驱动(当然asp.net也一定可以不需要,只是不知道咋搞)。



    那玩意儿是个好东西,不知道为什么研究的人这么少。

    记得我和lovecherry以前在VS2005的时候就眼馋VS的XSD自动生成代码。

    应该不需要web server的说,不是说XSD的代码也是它生成的么?
    资料太少了。

  45. 老赵
    admin
    链接

    老赵 2009-10-27 10:36:00

    @装配脑袋
    哦哦……怪不得,我在想XML Literal怎么生成非XML的东西呢。

  46. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 10:36:00

    Jeffrey Zhao:
    @Ivony...
    其实要我的话,就直接上T4 Tempalte了吧,就是纯粹asp.net的写法,只不过不需要web server驱动(当然asp.net也一定可以不需要,只是不知道咋搞)。



    用VB的一大特点就是不需要任何额外工具^_^
    我的生成代码小工具分发给其他组使用轻轻松松。连XAML/proj文件都能生成,XML用途很广泛。。

  47. 不要迷恋哥,哥只是个传说
    *.*.*.*
    链接

    不要迷恋哥,哥只是个传说 2009-10-27 10:54:00

    一般像这样的情况都是先拿StringBuilder拼接出字符串,然后拿xmldocument.load一下更简单。

  48. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 10:55:00

    有时间要把CodeDOM改造下,

    话说已经有LINQ to CodeDOM项目了么?有的快吱声。

    我很懒的,有人弄了我就不想弄了。

  49. 老赵
    admin
    链接

    老赵 2009-10-27 10:56:00

    @不要迷恋哥,哥只是个传说
    光XML转义就要搞死了,不转义的话,那堆双引号不也烦死啊。

  50. 老赵
    admin
    链接

    老赵 2009-10-27 10:57:00

    @Ivony...
    好像有好像没有,搜搜看?不过这个目的是什么?

  51. 老赵
    admin
    链接

    老赵 2009-10-27 11:04:00

    Ivony...:
    应该不需要web server的说,不是说XSD的代码也是它生成的么?
    资料太少了。


    嗯嗯,我就是说T4不需要。其实资料……也不算太少,当然的确是冷门组件。
    http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx

  52. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 11:06:00

    把CodeDOM改造的像LINQ to XML一样好用哈,例如:

    new CodeClassBuilder( "TestClass", 
      properties.Select( p => new CodePropertyBuilder( p.Type, p.Value ) )
    );
    

  53. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-10-27 11:10:00

    Property需要是TestClass类型怎么办啊。。

  54. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 11:17:00

    装配脑袋:Property需要是TestClass类型怎么办啊。。



    呃,这个,我再想想语法。。。。

  55. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 11:20:00

    Jeffrey Zhao:
    @Ivony...
    其实要我的话,就直接上T4 Tempalte了吧,就是纯粹asp.net的写法,还不需要web server驱动(当然asp.net也一定可以不需要,只是不知道咋搞)。



    赫赫 vs 给vb的xsd智能提示好啊 t4在这方面完全比不了

  56. 老赵
    admin
    链接

    老赵 2009-10-27 11:25:00

    @韦恩卑鄙
    我觉得可以尝试直接用asp.net的编辑器来编辑……

  57. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 11:26:00

    我尝试过 后来改成放弃t4的模板 用console 写一个输出 copy进t4了。。。。

  58. Gnie
    *.*.*.*
    链接

    Gnie 2009-10-27 11:44:00

    看不懂也看看~

  59. 不要迷恋哥,哥只是个传说
    *.*.*.*
    链接

    不要迷恋哥,哥只是个传说 2009-10-27 13:46:00


    Jeffrey Zhao:
    @不要迷恋哥,哥只是个传说
    光XML转义就要搞死了,不转义的话,那堆双引号不也烦死啊。



    有什么好搞死的,写出来然后在记事本里ctrl+H一替换就OK了。

  60. 不要迷恋哥,哥只是个传说
    *.*.*.*
    链接

    不要迷恋哥,哥只是个传说 2009-10-27 13:48:00

    @Jeffrey Zhao

    无非就是搭个架子,代码量又没多少,架子起来了,拿代码动态往里添数据就O了,代码量也没多少,也省事。没必要像你这样自己给自己找事……哈……

  61. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 13:55:00

    
          var c = new CB( "TestClass" );
          c.Build(
            properties: new[]
            {
              new PI( type: c, name: "A", get: null, set: null ),
              new PI( type: c, name: "B", get: null, set: null )
            }
          );
    


    和理想的写法还是有很大的差距啊。。。。

  62. 老赵
    admin
    链接

    老赵 2009-10-27 14:08:00

    @不要迷恋哥,哥只是个传说
    如果你说用XElement不复杂倒好说,XML转义哪有那么简单,看看这个:http://www.opentag.com/xfaq_charrep.htm
    你也可以反过来想,如果字符串拼接都那么容易,为什么每个语言/框架都要给一种XML构建方式——如果大家都在给自己找事,就说明这事情回避不得,呵呵。

  63. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 14:10:00

    Ivony...:
    VB对XML的支持不限于处理XML吧。其实是一个非常强大的特性,尤其是VB支持的混写模式,甚至于可以在XML内部使用ASP.NET语法,代码和XML之间无界限。

    这样的特性如果只是用来处理XML就太暴殄天物了,显然XML是一种非常良好的数据储存格式,很多时候比关系型数据更好用。

    不过VB如果能将XML Literal直接编译成强类型的对象,就更爽了。。


    只要提供xsd就几乎强类型了,,,,

  64. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 14:21:00

    Jeffrey Zhao:
    @韦恩卑鄙
    我觉得可以尝试直接用asp.net的编辑器来编辑……


    补充一下 t4在2008不支持lambda 不支持扩展方法 写起来那叫一个郁闷

  65. 老赵
    admin
    链接

    老赵 2009-10-27 14:23:00

    @韦恩卑鄙
    阿阿,真是弱。

  66. EricZhang(T2噬菌体)
    *.*.*.*
    链接

    EricZhang(T2噬菌体) 2009-10-27 14:26:00

    老赵玩标题党,哼哼。。。

  67. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-10-27 14:26:00

    等待c#和vb 合婚的那一天

  68. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 14:32:00

    其实C#的很多语法还有可以发掘的空间。

    譬如说?:三目运算符,最近发现其实这样写也不错:

          char ch = 'n';
          
          
          var o =
          ch == 'n' ? '\n' :
          ch == 't' ? '\t' :
          ch == 'r' ? '\r' :
          Item<char>.Error( new Exception( "Syntax Error" ) );
    



    总之,C#的潜力还没被挖尽啊。。。。

  69. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-10-27 14:33:00

    韦恩卑鄙:

    Jeffrey Zhao:
    @韦恩卑鄙
    我觉得可以尝试直接用asp.net的编辑器来编辑……


    补充一下 t4在2008不支持lambda 不支持扩展方法 写起来那叫一个郁闷



    强烈要求提供回忆录和开发笔记。

  70. DiggingDeeply
    *.*.*.*
    链接

    DiggingDeeply 2009-10-27 15:54:00

    @Ivony...
    我这么写过。

  71. ERic Poon
    *.*.*.*
    链接

    ERic Poon 2009-10-27 16:41:00

    呢個功能很好,語法實現簡單易懂。

  72. kobeen123[未注册用户]
    *.*.*.*
    链接

    kobeen123[未注册用户] 2009-10-27 18:22:00

    @DiggingDeepl
    我觉得可以尝试直接用asp.net的编辑器来编辑……

  73. liyou
    *.*.*.*
    链接

    liyou 2009-10-27 21:23:00

    好用多了。

  74. 我走了[未注册用户]
    *.*.*.*
    链接

    我走了[未注册用户] 2009-10-27 22:58:00

    最近博客园的全部文章订阅怎么没了!????

  75. _lsp[未注册用户]
    *.*.*.*
    链接

    _lsp[未注册用户] 2009-11-02 15:36:00

    找不到合适的地方,就在这儿问吧。 老赵看你其它感兴趣的程序语言有Erlang, F#, Haskell, Ruby等,涉及不同方面的语言。请问,是出于纯粹的兴趣,还是工作需要,还是因为不同的语言思想对人的思维有更好的启发?长期以来从事C系列语言的开发,我也在思考了解一下其它语言也许有什么帮助? 但一直没啥什么具体的方向。 请问有什么经验共享?

  76. 老赵
    admin
    链接

    老赵 2009-11-02 16:53:00

    @ _lsp
    研究各种语言纯粹是兴趣,只有一小部分对工作直接有帮助。
    我喜欢学习,比较,借鉴各种语言,启发还是挺大的。
    我觉得,你可以搞一下函数式编程,Haskell或F#比较好。

  77. Nana's Lich
    *.*.*.*
    链接

    Nana's Lich 2009-11-26 03:55:00

    之前看到这篇文章的时候就发现了这个事情,再次阅读的时候实在是忍不住想说了——“Ruby Markup Builder”的缩写岂不就是“RMB”?
    如果能用20行C#代码打造出RMB就好了——“直接编出钱来”可是很多人的梦想。

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我