每周源代码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还没有看过MonoLinq的支持,不过他使用了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端创建了同种类型和方法等。

怪异但很有趣!


Comments (0)

Skip to main content