Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to 'sneak' interface behind 3rd party objects

I am working with C#, .NET 4.5.
I have 2 objects (actually more but for sake of simplicity lets stick with two) that are separate entities and all come from 3rd party libraries, however they do have few common properties.

I want to do an abstract mechanism that would work with these properties. If these objects would be mine I could do it easily by adding interface

class Foo : IFooBar
{
    public string A { get; set; }
    public string B { get; set; }
}

class Bar : IFooBar
{
    public string A { get; set; }
    public string B { get; set; }
}

interface IFooBar
{
    string A { get; set; }
    string B { get; set; }
}

public static class Extensions
{
    public static IFooBar ProcessedFoobars(IFooBar fooBar)
    {
    ...(do things to A and B)
    }
}

However since they come from 3rd party I have no (don't know a) way of putting them behind interface.

Options I see ATM:

  1. Convert Foo and Bar to MyFoo and MyBar that are my internal objects put MyFoo and MyBar behind interface and handle them this way

  2. Use a method that accepts only properties as inputs.

    Tuple<string, string> DoThings(string A, string B)
    {
    ...(do things to A and B)
    }
    

This will involve lots of mapping from each flavour of 3rd party object.

  1. At this point I am leaning to using reflection.

    public T FooBarProcessor<T>(T fooBar)
    {
        var type = typeof (T);
        var propertyA = type.GetProperty("A");
        var propertyB = type.GetProperty("B");
        var a = propertyA.GetValue(fooBar, null);
        var b = propertyB.GetValue(fooBar, null);
        ... (do things to A and B)
        propertyA.SetValue(fooBar, a);
        propertyB.SetValue(fooBar, b);
        return fooBar;
    }
    

Is there a way to 'sneak' interface behind 3rd party objects (or some other workaround) that would allow me to make multiple objects seem as if they are behind interface, so I could deal with them all in same way.

What gives me hope that this could be done - there's PostSharp that does allows to do 'Aspect Inheritance' (haven't tried it myself, so it might be something different) in pay'd version and if they do this somehow - then this can be done.

like image 211
Matas Vaitkevicius Avatar asked Dec 19 '22 07:12

Matas Vaitkevicius


2 Answers

What you need is adapter pattern.

You can create classes that implements your interface and use Foo & Bar in the background:

interface IFooBar
{
    string A { get; set; }
    string B { get; set; }
}

class FooAdapter : IFooBar
{
    private readonly Foo _foo;

    public FooAdapter(Foo foo)
    {
        _foo = foo;
    }

    public string A
    {
        get { return _foo.A; }
        set { _foo.A = value; }
    }

    public string B
    {
        get { return _foo.B; }
        set { _foo.B = value; }
    }
}


class BarAdapter : IFooBar
{
    private readonly Bar _bar;

    public BarAdapter(Bar bar)
    {
        _bar = bar;
    }

    public string A
    {
        get { return _bar.A; }
        set { _bar.A = value; }
    }

    public string B
    {
        get { return _bar.B; }
        set { _bar.B = value; }
    }
}
like image 107
Ufuk Hacıoğulları Avatar answered Jan 04 '23 22:01

Ufuk Hacıoğulları


If you want a correct or most common solution you should follow Ufuk´s answer.

My solution provides a faster way to solve the problem, but in case of a longterm use this is not recommended.

When I understand your problem correct, you could try to use a method that accepts a dynamic object as parameter.

public static void ChangeCommonProperties(dynamic thirdPartyObject){
  thirdPartyObject.A = "Hello";
  thirdPartyObject.B = "World";
}

ChangeCommonProperties(new Foo());
ChangeCommonProperties(new Bar());

As long as the object passed in has the properties and the property type is correct, this works without problems. Otherwise you get a RuntimeBinderException with details what went wrong.

like image 20
Jehof Avatar answered Jan 04 '23 22:01

Jehof