Search code examples
c#.netreflectioncastle-dynamicproxy

No base class problem, How to use Castle.DynamicProxy Mixin in this particular case?


I have a 3rd party badly designed library that I must use.
It has all sorts of types it works with, we'll call them SomeType1, SomeType2 etc.
None of those types share a common base class but all have a property named Value with a different return type.
All I want to do is to be able to Mixin this class so I'll be able to call someType1Instance.Value and someType2Instance.Value without caring what the concreate type it is and without caring what the return type is (I can use object).
So my code is currently:

public interface ISomeType<V>
{
  V Value {get; set;}
}

public interface ISomeTypeWrapper
{
  object Value { get; set; }
}

public class SomeTypeWrapper<T> : ISomeTypeWrapper
    where T : ISomeType<???>
{
  T someType;

  public SomeTypeWrapper(T wrappedSomeType)
  {
    someType = wrappedSomeType
  }

  public object Value
  {
     get { return someType.Value; }
     set { someType.Value = value != null ? value : default(T); }
  }
}

public class SomeType1
{
  public int Value { get; set; }
}

public class SomeType2
{
  public string Value { get; set; }
}

The problem is that I don't know what T might be until runtime due to the fact that I get a dictionary of objects.

I can iterate the dictionary and use reflection to create a SomeWrapperType on runtime but I would like to avoid it.

How can I mixin the concreate type of SomeType to ISomeType?
How can I know what V type parameter is? (wish I had typedefs and decltype like in c++)

How can I, with the minimum of use of reflection possible Mixin those classes with the interface/base class?


Solution

  • You could try the Duck Typing Extensions for Windsor. It means you will need to register each of your types.

    container
        .Register(Component.For(typeof(SomeType1)).Duck<ISomeType>())
        .Register(Component.For(typeof(SomeType2)).Duck<ISomeType>());
    

    You could probably use linq and the register AllTypes syntax to reduce code if the names are similar.

    Alternatively in the short term create a factory which can return you the objects you need, implement a concrete object for each type. No you are using the interface you can remove the factory at a later date and replace it with something else with minimal impact:

    public class SomeTypeWrapperFactory
    {
        public ISomeType<int> CreateWrapper(SomeType1 someType1)
        {
            return new SomeType1Wrapper(someType1);
        }
    
        public ISomeType<string> CreateWrapper(SomeType2 someType2)
        {
            return new SomeType2Wrapper(someType2);
        }
    }
    
    public class SomeType1Wrapper : ISomeType<int> { ... }
    public class SomeType2Wrapper : ISomeType<int> { ... }
    

    Regardless of how you implement the wrapper, be the individually or using a god like class you have the ability to change how the wrapping is done and keep the rest of your code clean.