.NET和Silverlight之间的共享代码的可行性?

5
刚刚经历了一次小的实验,试图看看将我们的.NET类库或至少部分内容带入Silverlight以便在两个世界之间重用业务逻辑需要多少工作量。我想知道其他人是否有这方面的经验。
以下是我注意到的一些事情:
- 缺少很多属性(例如Browsable(false)) - 缺少很多接口,或者存在但为空(ICloneable被隐藏,ITypedList缺失) - 反射差异(所有可访问的内容都需要公开) - 一些基础类别的不同(没有Component?)
所以我想知道,我是否真的可以将其视为可能性?
我成功运行了初始代码,但我不得不注释掉整个基本功能,主要是处理列表,因为它们基于ITypedList和一些基础类别。显然,我需要在Silverlight中更改为ObservableCollection,因此需要更改大量基础代码以进行应对。
我创建的实际业务测试类与我将为.NET创建的类几乎完全相同,只有一些较小的更改,在.NET中也可以轻松使用,只不过在查看Silverlight之前我没有这样做。换句话说,如果我能使基础类别兼容,那么重用业务逻辑似乎是可行的。
我的意思是,我基本上会有两个项目文件,一个用于.NET,另一个用于Silverlight,但实际的C#源代码是相同的,在两者之间共享。
那么有人有这方面的经验吗?有什么提示或指南吗?
它值得吗?它肯定值得更深入地研究。
4个回答

4

这绝对是可行的。

我们这里的一个项目已经使用了这种方法,Silverlight项目包括C#项目,使用了一些#IF语句来处理一些事情(例如log4net声明),或者有时候会重新实现一些东西。但总的来说,这是一个巨大的胜利,你一定要尝试一下(而且我们已经成功地做到了)。

-- 编辑:

有一点需要注意的是,我们的OR/M(LLBLGen)没有内置支持将“简单”对象发送到Silverlight;但有人编写了一个插件来处理它,这很有帮助。因此,你可能需要考虑你正在使用什么样的数据访问层(DAL),以及它对Silverlight的支持程度。


好的,那么我假设你没有遇到任何无法克服的问题。听到这个消息很好,那么我一定会继续进行这个项目。 - Lasse V. Karlsen
Lasse:肯定有一些东西缺失;我想不起来了,但是一些反射的东西,log4net等等。但这绝对是可以克服的;(虽然,在至少VS2008中,有时会出现一些“奇怪”的问题;当您使用“添加为链接”从主项目添加现有类并更改它时,您必须通过Silverlight项目打开它(实际上打开它)才能识别更改)。尽管如此,没有毁灭灵魂的问题 :) - Noon Silk
好的。看起来最大的问题是我必须重新实现我们列表类的基础,因为我们在业务逻辑中经常使用列表,并且我们有一些特殊的列表类知道它们处于“业务逻辑世界”中,但是看看ObservableCollection的使用方式,它似乎会做我们需要的事情,只需要改变代码来应对它。我们的IoC容器可以工作,但没有app.config配置,但我们也不会在这里使用它。只是想知道是否有其他人发现了我没有立即看到的任何雷区。 - Lasse V. Karlsen
Lasse:是的,如果你在自己的集合属性中实现ObservableCollection,你将能够充分利用它(这也是我们所做的,效果很好)。 - Noon Silk
我们为数据类生成自己的代码,但由于 SQL 不会在客户端应用程序中执行,因此我们可能需要找到一种良好的方式从服务器传输这些对象。 - Lasse V. Karlsen
Lasse:确实,这就是我们使用的(一些简单的DTO);当然,所有实际获取数据的调用(如果需要)都是通过WebServices完成的(而不是在客户端上使用SQL;那将是疯狂的!:)。 - Noon Silk

4
我为了方便做了以下几点:
  1. 经常使用部分类和#if !SILVERLIGHT将代码分成Silverlight可以处理的部分。
  2. 尽可能使用代码生成。例如,我一直在尝试使用T4模板来生成Silverlight等效属性(DisplayAttribute而不是DescriptionAttribute)。
  3. 每当Silverlight没有实现接口/属性(例如IDeserializationCallback、ICloneable、INotifyPropertyChanging)时,只要知道不会使用实现不是问题,我就会在Silverlight应用程序中创建一个同名的虚拟接口。
  4. 最后,值得注意的是,在Silverlight 4中,程序集格式允许在Silverlight和.NET之间共享二进制文件,只要没有Silverlight不支持的依赖项。

关于单独的基类还有一个注意事项-创建一个抽象类,它从ObservableCollection派生到Silverlight和BindingList(或者你在.NET中使用的任何东西)来最小化对你的类型化集合的影响。

更新 今天我正在将一些大量使用System.Diagnostics API(如TraceSource、SourceSwitch等)的.NET代码移植到Silverlight,但这些API在Silverlight中不存在。我在Silverlight项目中创建了这些API的非常简单的实现,并将它们放在Einstein.Diagnostics命名空间中。在这样做的过程中,我决定需要一个约定来轻松地识别模仿.NET Framework的代码和我的自己的代码。因此,我将占位符文件重命名为以@符号为前缀的文件。我还在这些文件的类名前加了前缀。好处是@符号实际上不会改变它们的类名,就C#编译器而言。因此,@SourceSwitch仍然编译为Einstein.Diagnostics.SourceSwitch,但在代码中,我可以很容易地看出有问题。我还用[SilverlightPlaceholder]属性装饰了这些类。


我肯定会查看在基类中修复 ObservableCollection 依赖项的问题。很高兴了解到 Silverlight 4,但不幸的是我们可能无法立即采用它。除了 ITypedList 外,我认为我遇到的任何接口都不会造成问题。至于我们的业务逻辑类,它们已经使用代码生成器构建,尽管这是我们自己的工具,但我们需要要求它进行修复以实现100%的兼容性,这很容易完成。感谢您的意见!在我已经收到的两个答案之间,我已经足够放心去进行初始更新了。 - Lasse V. Karlsen

2
我使用protobuf-net来进行此操作,并采用了一些方法:
- 在项目文件中使用条件编译符号来触发微妙的代码分支(是的,它不完美,但它有效)。 - 重新引入某些内容;属性可能是一个例子 - 您的代码仍然可以使用重新引入的属性,即使框架代码不支持;作为这个的更极端的例子,对于紧凑框架,我不得不重新引入好块的Expression API,这很有趣。 - 只需放弃一些东西 ;-p 然而,如果您正在使用ITypedList(如您所提到的),我可以看到整个方法会变得非常混乱;组件模型已经足够复杂了,不必再通过这些hack方式来强制实现。这确实取决于您在这条路上走了多远。也许4.0 / dynamic将再次打开其中一些选项?

实际上,我们使用ITypedList,因为它让我们能够轻松地绑定到大多数正在使用的网格组件,支持子属性。也就是说,我可以绑定到“Employee.FirstName”,其中Employee是列表中对象的属性。我还不知道这是否适用于ObservableCollection,但如果是,我们将处理这些更改。 - Lasse V. Karlsen
类库中包含大量可能不需要的内容,我们将使用条件编译来处理许多事情。例如,我有一个堆类,我们使用它来实现非泛型集合接口,如IList和ICollection,但我注意到Silverlight中缺少这些接口,因此我们将使用一些巧妙的#if指令来忽略这些部分。 - Lasse V. Karlsen
实际上,在Silverlight中,数据绑定的方式比Windows Forms更加灵活,因此您所描述的情况(绑定到子属性)不需要像ITypedList那样费力。看一下属性路径绑定语法,你就会明白我的意思:http://msdn.microsoft.com/en-us/library/cc645024(VS.95).aspx - Josh
@Josh -- 如果你要绑定的对象包含一个名称/值对的映射,该怎么办?我唯一能想到的方法是通过绑定表达式中的字符串索引器来实现。你能对此发表评论吗? - Drew Noakes

2

你遇到的问题可能有一个解决方法是从Mono项目中复制缺失的代码。 回想起来,我曾经做了一个使用Compact Framework的小项目,它缺少整个System.XLM命名空间。 我只需将整个内容从Mono复制到我的项目中,编译它并进行最少的更改,就可以很好地工作,如果我没记错的话。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接