每周源代码16 – 胶布版(Duct Tape Edition)
[原文发表地址] The Weekly Source Code 16 - Duct Tape Edition
[原文发表时间] 2008-02-20 22:01
几周前,我采访了Panic合伙人,Mac开发人员之一的Steven Frank(博客),他也是我的大学校友。自那次采访之后,我偶然发现了最近发布的NSDuctTape项目。首先,对一个叫做胶布(Duct Tape)的项目,你怎么会不喜欢呢?其次,我只要听到某些代码可以解决不一致或无法连接的东西,都会去看看的。就是说,如果有怪人承诺要将两样事物连接起来,我就超级想看一下!
NSDuctTape是一个niche,不过如果你想在Mac上使用Mono编写.NET代码,并且你想访问Objective C cocoa库,这儿就是你的一站式商店。(注意:如果你想下载他的源代码,你可能要把文件一个个拉出来,因为zip包里的Mac文件有和文件夹同名的,而Windows并不喜欢这样。)
所以,亲爱的读者,我在这里奉上第16篇“每周源代码”,之后还会继续。这是我这周在读的一些源代码。
代码的作者Dave还没有看过Mono对Linq的支持,不过他使用了C#3.0的功能来创建他自己的LINQ-lite 辅助函数。我觉得这很聪明。
internal static class Enumerable
{
public static
IEnumerable Select(IEnumerable list, Converter convert)
{
foreach (TInput value in
list)
yield return convert(value);
}
public static IEnumerable SelectMany(IEnumerable list,
Converter> convert)
{
foreach (TInput value in
list)
foreach (TOutput converted in
convert(value))
yield return converted;
}
public static IEnumerable Where(IEnumerable list,
Predicate predicate)
{
foreach (T value in
list)
if
(predicate(value))
yield return value;
}
public static List ToList(IEnumerable
list)
{
List
result = list as List;
return
result ?? new List(list);
}
public static T[] ToArray(IEnumerable
list)
{
return ToList(list).ToArray();
}
}
因为他深刻的”thunking”(思考)(虽然并非确切术语,但我喜欢这样说)使用到了非托管代码,这就需要处理分配和释放的问题,所以他用我最喜欢的.NET BCL 模型和Idisposable创建了一个HGlobal封装类。堪称经典,简单有效。
...snip...
public void Dispose()
{
if (_hGlobal != IntPtr.Zero)
Marshal.FreeHGlobal(_hGlobal);
_hGlobal = IntPtr.Zero;
}
private DisposableHGlobal(IntPtr hGlobal)
{
_hGlobal = hGlobal;
}
public static DisposableHGlobal StructureToHGlobal(T value)
where T : struct
{
DisposableHGlobal result = new DisposableHGlobal(Marshal.SizeOf(value));
Marshal.StructureToPtr(value, result.ToIntPtr(), false);
return result;
}
...snip...
最后,在他应用程序管理的“wrapper”中,通过把System.Types做技术处理,将他们一 一用ObjectiveC注册。这种互操作是一种方式,表示他选择把.NET 类型作为Objective C 类来呈现。
public static void Run(string nibFile, IEnumerable exposedTypes)
{
ObjectiveCClass nsAutoReleasePoolClass = ObjectiveCClass.GetClass("NSAutoreleasePool");
IntPtr autoReleasePool = nsAutoReleasePoolClass.Instantiate();
ObjectiveCMethods.SendMessage(autoReleasePool, ObjectiveCMethods.SelectorFromString("init"));
try
{
IntPtr process = IntPtr.Zero;
GetCurrentProcess(ref process);
TransformProcessType(ref process, ProcessType.ForegroundApplication);
SetFrontProcess(ref process);
Registrar.Initialize();
foreach (Type type in exposedTypes)
{
ObjectiveCNameAttribute attribute = MemberInfoUtility.GetCustomAttribute(type);
Registrar.RegisterClass(attribute != null ? attribute.Name : type.Name, type);
}
ObjectiveCClass nsBundleClass = ObjectiveCClass.GetClass("NSBundle");
IntPtr name = NativeString.StringToNativeString(nibFile);
ObjectiveCClass nsDictionaryClass = ObjectiveCClass.GetClass("NSDictionary");
IntPtr key = NativeString.StringToNativeString("NSOwner");
ObjectiveCClass nsApplicationClass = ObjectiveCClass.GetClass("NSApplication");
IntPtr sharedApplication = ObjectiveCMethods.SendMessage(nsApplicationClass.ToIntPtr(), ObjectiveCMethods.SelectorFromString("sharedApplication"));
IntPtr nsDictionary = ObjectiveCMethods.SendMessage(nsDictionaryClass.ToIntPtr(), ObjectiveCMethods.SelectorFromString("dictionaryWithObject:forKey:"), sharedApplication, key);
IntPtr zone = ObjectiveCMethods.SendMessage(sharedApplication, ObjectiveCMethods.SelectorFromString("zone"));
ObjectiveCMethods.SendMessage(nsBundleClass.ToIntPtr(), ObjectiveCMethods.SelectorFromString("loadNibFile:externalNameTable:withZone:"), name, nsDictionary, zone);
ObjectiveCMethods.SendMessage(sharedApplication, ObjectiveCMethods.SelectorFromString("run"));
}
finally
{
ObjectiveCMethods.SendMessage(autoReleasePool, ObjectiveCMethods.SelectorFromString("release"));
autoReleasePool = IntPtr.Zero;
}
}
在RegisterClass里他为每一个.NET类都创建了一个Objective C类,并简洁的做了类定义和赋值操作。他在两处都使用了“反射”技术,反射.NET类型,方法等,并且动态的在ObjectiveC端创建了同种类型和方法等。
怪异但很有趣!