You can solve this by using strong named assemblies and the TypeForwardedToAttribute.
First, give your PCL assembly a strong name by signing it, preferably by adding an AssemblyKeyFileAttribute
to the AssemblyInfo.cs file. More details are found here.
Next, add a simple DBNull
class with sufficient contents. Here is an example, modify it to your own content:
namespace System
{
public sealed class DBNull
{
public static readonly DBNull Value = new DBNull();
private DBNull() { }
}
}
Now, you will need to create target specific assemblies with the same strong name and version as the PCL assembly. These assemblies will replace the PCL assembly in the target specific applications making use of DBNull
. If this should work, it is absolutely necessary that the strong name and version are the same. If the signing file is referenced in the AssemblyInfo.cs file of the PCL project, one efficient approach is simply to add (with a link) this file to the target specific project instead of the auto-generated AssemblyInfo.cs file. Also, in the project settings, make sure that the assembly name is the same for the target specific and PCL libraries.
In the .NET Framework and Windows Phone libraries replacing the PCL library, you should now add a .cs file, for example called TypeForwarding.cs, with the following contents:
using System;
using System.Runtime.CompilerServices;
[assembly: TypeForwardedTo(typeof(DBNull))]
When this assembly is referenced (replacing the PCL assembly), the compiler will then know that it should look for the existing DBNull
implementation in the target framework.
On the other hand, in the Windows Store (WinRT) library replacing the PCL, you should include the same DBNull
source file that you included in the PCL library, since WinRT does not contain a pre-existing implementation of DBNull
.
EDIT
First of all, a very important note! If you are using TypeForwardedToAttribute
, the method or property signature in the PCL assembly must be exactly the same as the signature in the target specific consumer assembly. Otherwise the method/property will not be properly identified in the end-user application. I usually consult the MSDN documentation to obtain the correct signatures.
It also crucial that if you are using type forwarding for enum
types, the numeric values of the enums must be equal to the target specific implementations. A resource that is very helpful when identifying these values is the Mono source code.
Whether you should use non-functional stubs in your PCL assembly varies from type to type, and as far as I know there is no specific support for generating consumer project assemblies from a PCL.
For example, there are some types that are available on the three targets .NET, Windows Store and Windows Phone 8, but not in PCL, like the Marshal
and GCHandle
classes. In this case you would provide unimplemented methods in your PCL like this:
public static class Marshal
{
public static IntPtr AllocHGlobal(int cb) {
throw new NotImplementedException();
}
}
and then use type forwarding in all your consumer libraries:
[assembly: TypeForwardedTo(typeof(Marshal))]
On the other hand, there are types that are available on some but not all of the targets, and not in PCL.
In that case, if it is appropriate, you can include a working implementation in the PCL (as suggested in the original answer) and include that same implementation in the consumer project for the target that is missing this type.
If it impractical or impossible to provide a PCL implementation that works with any target, you could instead include a non-functional stub in the PCL, and provide a target specific implementation in the consumer projects.