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

Mat*_*hew 6 c# types windows-phone portable-class-library windows-runtime

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

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

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

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

And*_*son 7

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

首先,通过签署它,最好加入一个给你的PCL集强名称AssemblyKeyFileAttribute的AssemblyInfo.cs文件.更多细节可在此处找到.

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

namespace System
{
  public sealed class DBNull
  {
    public static readonly DBNull Value = new DBNull();
    private DBNull() { }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

using System;
using System.Runtime.CompilerServices;

[assembly: TypeForwardedTo(typeof(DBNull))]
Run Code Online (Sandbox Code Playgroud)

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

在另一方面,在Windows应用商店(WinRT的)库替换PCL,你应该包括同DBNull您在PCL库中包含的源文件,因为WinRT中并没有包含现有的预执行DBNull.

编辑

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

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

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

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

public static class Marshal
{
  public static IntPtr AllocHGlobal(int cb) {
    throw new NotImplementedException();
  }
}
Run Code Online (Sandbox Code Playgroud)

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

[assembly: TypeForwardedTo(typeof(Marshal))]
Run Code Online (Sandbox Code Playgroud)

另一方面,有些类型可用于某些但不是所有目标,而不是PCL.

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

如果提供与任何目标一起使用的PCL实现是不切实际或不可能的,则可以在PCL中包含非功能性存根,并在消费者项目中提供目标特定实现.