Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / C#

Injecting an interface into unrelated types via partial classes

Rate me:
Please Sign up or sign in to vote.
4.33/5 (4 votes)
20 Nov 2017CPOL2 min read 13.1K   3   6
This how-to article explores an approach using partial classes to inject a common interface into unrelated types that are auto-generated from web services or other external sources

Introduction

Recently I was working on some code that was pulling data objects off a remote WCF OAuth API. Visual Studio auto-generated the proxy classes for the data entities, and it was all good. There was one glitch though. While the various entity classes had several common properties such as IsDeleted, IsActive, etc. they did not share a base class or interface. So while we had methods that looped through these objects and did pretty much identical tasks against these properties, we could not use a common method as these were seemingly unrelated classes. Luckily, they were all partial classes, which meant we could use that to inject a common base interface to these classes. This article describes this approach.

Example code

This is a dumbed down example, so it will seem rather contrived. Use your imagination to transform this to a more realistic scenario.

C#
namespace LibraryY
{
    public partial class ObjectY
    {
        public bool IsDeleted { get; set; }

        public bool IsDisabled { get; set; }

        public bool IsInActive { get; set; }

        public static ICollection<ObjectY> GetItems()
        {
            return new[] { new ObjectY() };
        }
    }
}

And here's a second unrelated class with no common base interface or class. Even in a different namespace.

C#
namespace LibraryX
{
    public partial class ObjectX
    {
        public bool IsDeleted { get; set; }

        public bool IsDisabled { get; set; }

        public bool InActive { get; set; }

        public static ICollection<ObjectY> GetItems()
        {
            return new[] { new ObjectX() };
        }
    }
}

Notice how they have two properties that have identical names.

  • IsDeleted
  • IsDisabled

They also have a property each, which represents the same logical meaning but are named differently

  • ObjectX.InActive
  • ObjectY.IsInActive

The partial class trick works for the first scenario, same names. For the different-names scenario, I discuss a different approach for the sake of completion. But that's not set in stone, so you may have other preferred workarounds.

Injecting the interface

Essentially, there are two steps here. Step 1 is to define an interface with the commonly named properties.

C#
namespace InterfaceInjector
{
    interface ICommonInterface
    {
        bool IsDeleted { get; set; }
        bool IsDisabled { get; set; }
    }
}

And step 2 is to use partial classes to extend the unrelated classes and apply this interface

C#
namespace LibraryX
{
    public partial class ObjectX : InterfaceInjector.ICommonInterface { }
}

namespace LibraryY
{
    public partial class ObjectY : InterfaceInjector.ICommonInterface { }
}

That's it, really. Here's some test code showing this in action

C#
    var xItems = LibraryX.ObjectX.GetItems();

    foreach (var item in xItems)
    {
        Handle(item);
    }

    var yItems = LibraryY.ObjectY.GetItems();

    foreach (var item in yItems)
    {
        Handle(item);
    }

// . . . 

private static void Handle(InterfaceInjector.ICommonInterface item)
{
    if(item.IsDeleted)
    {
        // handle delete
    }

    if(item.IsDisabled)
    {
        // handle disable
    }
}

So, we have a common shared method processing objects that are unrelated. Well, techncially we've forced them to be in a sort of relationship here. Alright, so what about the other scenario? As mentioned, you can do this is multiple ways, and here's one easy way to do this. This approach defines a wrapper class per differently named property in the unrelated classes that all work the same way logically (this is for you to ascertain).

C#
interface IActiveStatus
{
    bool IsInActive { get; set; }
}

public class ActiveStatusWrapper<T> : IActiveStatus
{
    T item;
    Func<bool> getter;
    Action<bool> setter;

    public ActiveStatusWrapper(T item, Func<bool> getter, Action<bool> setter)
    {
        this.item = item;
        this.getter = getter;
        this.setter = setter;
    }

    public bool IsInActive
    {
        get
        {
            return getter();
        }

        set
        {
            setter(value);
        }
    }

    public T Item { get { return item; } }
}

Now you would just need to define a method to handle this new interface.

C#
private static void Handle(IActiveStatus activeStatusItem)
{
    if(activeStatusItem.IsInActive)
    {
        // handle inactive
    }
}

When passing the objects to the method, create an instance of the wrapper and pass the getter/setter methods.

C#
var xItems = LibraryX.ObjectX.GetItems();

foreach (var item in xItems)
{
    Handle(item);
    Handle(new ActiveStatusWrapper<ObjectX>(item, 
        () => item.InActive, (v) => item.InActive = v));        
}

var yItems = LibraryY.ObjectY.GetItems();

foreach (var item in yItems)
{
    Handle(item);
    Handle(new ActiveStatusWrapper<ObjectY>(item, 
        () => item.IsInActive, (v) => item.IsInActive = v));
}

You can clean this up a little better by using reflection to invoke the getter/setter methods. That way you don't need to instantiate function and action objects for each object. That said, compared with the additional cost of relection, you may want to compare the two approaches for performance before making a call there.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Nish Nishant is a technology enthusiast from Columbus, Ohio. He has over 20 years of software industry experience in various roles including Chief Technology Officer, Senior Solution Architect, Lead Software Architect, Principal Software Engineer, and Engineering/Architecture Team Leader. Nish is a 14-time recipient of the Microsoft Visual C++ MVP Award.

Nish authored C++/CLI in Action for Manning Publications in 2005, and co-authored Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on CodeProject.com and another 250+ blog articles on his WordPress blog. Nish is experienced in technology leadership, solution architecture, software architecture, cloud development (AWS and Azure), REST services, software engineering best practices, CI/CD, mentoring, and directing all stages of software development.

Nish's Technology Blog : voidnish.wordpress.com

Comments and Discussions

 
Questionpublic static ICollection<ObjectY> GetItems() Pin
eng.RHKhan7-Feb-18 1:46
eng.RHKhan7-Feb-18 1:46 
QuestionThis only works inside a single assembly and isn't really injecting anything. Pin
Dismember22-Nov-17 21:45
Dismember22-Nov-17 21:45 
AnswerRe: This only works inside a single assembly and isn't really injecting anything. Pin
Nish Nishant23-Nov-17 4:35
sitebuilderNish Nishant23-Nov-17 4:35 
QuestionImprove IActiveStatus implementation Pin
InbarBarkai20-Nov-17 19:27
InbarBarkai20-Nov-17 19:27 
AnswerRe: Improve IActiveStatus implementation Pin
Nish Nishant21-Nov-17 0:46
sitebuilderNish Nishant21-Nov-17 0:46 
GeneralRe: Improve IActiveStatus implementation Pin
Member 1127135820-Dec-17 21:48
Member 1127135820-Dec-17 21:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.