使用某些平台上存在的实际类型处理PCL中的缺失类型

这可能是某个问题的答案,但我似乎无法找到答案。

我正在开发一个将Mono.Data.Sqlite移植到Windows Phone和Windows Store的项目,但当然这也需要移植System.Data。 我决定使用PCL,因为这样就不需要为平台单独组装了(我也检查了Silverlight,但这不是优先考虑的事情)在这样做的过程中,除了一种类型之外,我设法获得了大部分function – DBNull 🙁

这就是问题所在,WP和SL声明了DBNull,但WinRT却没有。 是否可以在单个程序集中执行某些操作以在其存在的平台(WP和SL)上使用本机DBNull并在WinRT上使用自定义实现? 我似乎没有办法做到这一点。 我查看了其他解决方案:(a)为SL和WP创建PCL并排除DBNull类型和WinRT的另一个程序集,或者(b)创建一个引用WP和SL的自定义程序集的单个程序集,其类型转发到DBNull的本机实现,以及用于实现DBNull的RT的程序集。

有没有其他方法,或哪一个更好?

您可以使用强命名程序集和TypeForwardedToAttribute来解决此问题。

首先,通过签名为您的PCL程序集提供一个强名称,最好是将AssemblyKeyFileAttribute添加到AssemblyInfo.cs文件中。 更多细节可在此处找到。

接下来,添加一个具有足够内容的简单DBNull类。 这是一个示例,将其修改为您自己的内容:

 namespace System { public sealed class DBNull { public static readonly DBNull Value = new DBNull(); private DBNull() { } } } 

现在,您需要创建具有与PCL程序集相​​同的名称和版本的目标特定程序集。 这些组件将替换使用DBNull的目标特定应用程序中的PCL组件。 如果这应该有效,那么强名称和版本是绝对必要的。 如果在PCL项目的AssemblyInfo.cs文件中引用了签名文件,则一种有效的方法是将此文件(通过链接)添加到目标特定项目而不是自动生成的AssemblyInfo.cs文件。 此外,在项目设置中,确保目标特定和PCL库的程序集名称相同。

在替换PCL库的.NET Framework和Windows Phone库中,您现在应该添加.cs文件,例如名为TypeForwarding.cs ,其中包含以下内容:

 using System; using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(DBNull))] 

当引用此程序集(替换PCL程序集)时,编译器将知道它应该在目标框架中查找现有的DBNull实现。

另一方面,在Windows Store(WinRT)库中替换PCL,您应该包含您在PCL库中包含的相同DBNull源文件,因为WinRT不包含预先存在的DBNull实现。

编辑

首先,一个非常重要的说明! 如果使用的是TypeForwardedToAttribute ,则PCL程序TypeForwardedToAttribute的方法或属性签名必须与目标特定的使用者程序TypeForwardedToAttribute的签名完全相同 。 否则,最终用户应用程序中将无法正确识别方法/属性。 我通常会查阅MSDN文档以获取正确的签名。

同样重要的是,如果您对enum类型使用类型转发,则enum的数值必须等于特定于目标的实现。 识别这些值时非常有用的资源是Mono源代码 。

您是否应该在PCL程序集中使用非function存根因类型而异,据我所知,没有特定支持从PCL生成使用者项目程序集。

例如,在.NETWindows StoreWindows Phone 8这三个目标上有一些类型可用,但在PCL中没有 ,例如MarshalGCHandle类。 在这种情况下,您将在PCL中提供未实现的方法,如下所示:

 public static class Marshal { public static IntPtr AllocHGlobal(int cb) { throw new NotImplementedException(); } } 

然后在所有使用者库中使用类型转发:

 [assembly: TypeForwardedTo(typeof(Marshal))] 

另一方面,某些但不是所有目标都有类型,而不是PCL。

在这种情况下,如果合适,您可以在PCL中包含一个工作实现(如原始答案中所建议的那样),并在消费者项目中包含缺少此类型的目标的相同实现。

如果提供适用于任何目标的PCL实现是不切实际或不可能的,则可以在PCL中包含非function性存根,并在消费者项目中提供特定于目标的实现。

虽然Anders方法在技术上是合理的(并且正是我们实现.NET Core的“现代”表面区域)但它并非没有挑战。

如果您只对从您自己的应用程序重用的库使用此方法,那么它可以很好地工作。 但是,如果您希望将组件发送给第三方(例如,通过NuGet),则此方法不会扩展,因为生态系统必须就不包含该类型的平台上的一个表示达成一致。 这就是为什么我们继续提供可移植性包,例如Microsoft.Bcl.Async ,我们为社区工作。

System.Data在我们的雷达上,特别是System.Data.Common这样我们就可以启用第三方SQL提供程序,例如SQLite,在所有平台上共享抽象和公共实用程序( DBNull )。 我们没有这项工作的ETA,但它肯定在我们的TODO名单上。