Intro: Before showing the actual code for review, let me show you an ExampleClass
to create a shim for.
using System.Windows;
public class ExampleClass
{
public void ExampleMethod(string line) { MessageBox.Show(line); }
}
The target API of ExampleClass
had been .net framework
, before some new requirements came to make it multitargeted (both .net framework
and .net core 2.0
).
One solution is to create a Shim for ExampleClass
. This Shim should have ExampleMethod(..)
implemented for two APIs. The shim itself should be working on both APIs.
Code for Review, my first approach to shimming:
Base Shim
:
public class Shim
{
public object Obj { get; private set; }
public Shim(object defaultObject)
{
Obj = defaultObject;
}
}
//it is possible to create
//two platform specific counterpart classes for ExampleClass
//but i don't like this idea because it implies additional work
My multitargeted Shim for ExampleClass
:
#if NETFULL
using System.Windows;
#endif
namespace PortabilityLibrary.Shims
{
public class ExampleClassShim: Shim
{
public ExampleClassShim(object obj):base(obj) { }
public void ExampleMethod(string line)
{
#if NETFULL
if (Obj is ExampleClass)
((ExampleClass)Obj).ExampleMethod(line);
else
throw new Exception();
#elif NETCORE
if (Obj is NetCoreExampleClass)
((NetCoreExampleClass)Obj).ExampleMethod(line);
else
throw new Exception();
#endif
}
}
}
The following is no more for review, it could help to better understand the issue:
The way I could use the code from a .net framework
assembly:
public class ExampleCode
{
public static void Do()
{
var x = new ExampleClassShim(new ExampleClass());
x.ExampleMethod("For example...");
}
}
My sdk-style .csproj
file to make clear about NETFULL
and NETCORE
:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup><TargetFrameworks>netstandard2.0;netcoreapp2.0;net461</TargetFrameworks></PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' OR '$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>NETCORE;</DefineConstants></PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net461'">
<DefineConstants>NETFULL;</DefineConstants></PropertyGroup>
</Project>
Ok, just in case, a little bit more explanation:
NetCoreExampleClass
:
public class NetCoreExampleClass
{
public void ExampleMethod(string line) { Console.WriteLine(line); }
}
NetCoreExampleCode
, the way I could use the code from a .net core 2.0
assembly:
public class NetCoreExampleCode
{
public static void Do()
{
var x = new ExampleClassShim(new NetCoreExampleClass());
x.ExampleMethod("For example...");
}
}
Shim
with conditional compilation (#if NETFULL
) and not conditional compilation for the real implementation? \$\endgroup\$.net framework
objects likeMenuItem
(objects where i cannot change the code inside). The other thing is that i heard conditional compilation to be some variety of a code smell. Therefore, the reason for shimming could be to avoid repeated usage of conditional compilation, but only to have it in specialPortabilityLibrary
. \$\endgroup\$