Skip to content

Utility for creating a dynamic object facade/proxy to allow for using an object as an interface that it does not explicitly implement

License

Notifications You must be signed in to change notification settings

IFYates/IFY.Shimr

Repository files navigation

Shimr

Utility for creating a dynamic object facade/proxy to allow for using an object as an interface that it does not explicitly implement.

Build & Test Codacy Coverage Mutation testing badge Codacy Grade

NuGet Version NuGet Downloads

Formerly known as Shimterface: NuGet Version NuGet Downloads

Description

I'm sure we've all been in the situation where we've had to make use of a class from an external library (including mscorlib) that either doesn't implement any interface or doesn't implement one that can be used for any kind of Inversion of Control usage. One approach is to implement a series of proxy objects that handle all of the required functionality, including proxies around returned values, and this can even be scripted (Powershell, T4, etc.) to prevent the arduous task of proxying every class you need.

You might also be frustrated that classes can't have an identical interface applied to them post-design. e.g.,

public class TestClass {
    public void Test() {
        ...
    }
}
public interface ITest {
    void Test();
}

ITest forcedCast = (ITest)new TestClass();

Given that TestClass implements all of ITest members, logically this would be a lovely language feature. Instead, we get a runtime InvalidCastException.

Shimr solves and takes the effort out of this problem by compiling dynamic proxies to convert classes to the requested interface. The above example can be fixed using Shimr by doing:

ITest forcedCast = new TestClass().Shim<ITest>();

If you ever needed the original back again, then you simply unshim it:

TestClass originalObject = ShimBuilder.Unshim<TestClass>(forcedCast);

The wiki contains lots more examples and detailed coverage of usage.

Breaking changes

See the breaking change wiki.

Design principal

The purpose of Shimr is to improve testability and inversion-of-control; therefore, all behavioural decisions are designed to be implemented as application design-time. This is not a mocking library.

Outside of setting up your DI/IOC container and facades, if you're referencing Shimr directly, it's likely that you're thinking about a different problem domain to the one solved by this library.

Known Issues

  • If the compilation of the proxy type fails but the application handles it, the Type-Interface combination is now not usable

Future Ideas

  • Generate assembly of compiled shims for direct reference
  • Combine multiple target types to single shim
  • Behavioural configuration to attributes (e.g., [Shim(IgnoreMissingMembers = true)])

About

Utility for creating a dynamic object facade/proxy to allow for using an object as an interface that it does not explicitly implement

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages