menu

秋梦无痕

一场秋雨无梦痕,春夜清风冻煞人。冬来冷水寒似铁,夏至京北蟑满城。

Avatar

转贴一段C#代码

from: https://gist.github.com/5ab9961fc8b2454a4531
作者: Jeffrey Zhao

使用静态地动态类型(statically dynamic typing),二十行代码在C#中搞定Ruby Markup Builder的基本功能(当然不够完整)

// XmlMarkupBuilder.cs
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;
}
}

class Program {
static void Main(string[] args) {
dynamic b = new XmlMarkupBuilder();
XElement xml =
b.Persons(
b.Person("Tom", age: 10),
b.Person("Jerry", age: 8));

Console.WriteLine(xml);
// output:
// <Persons>
// <Person age="10">Tom</Person>
// <Person age="8">Jerry</Person>
// </Persons>
}
}


从dynamic关键字上可以看出,这是C# 4.0中新增的功能。
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是C# 3.5的新特性)。而age: 10这样的代码使用了命名参数(Named Parameters)(C# 4.0的新特性)。

评论已关闭