var mergedInstance = MergeFactory<InterfaceOne, InterfaceTwo>();
((InterfaceOne)mergedInstance).InterfaceOneMethod();
((InterfaceTwo)mergedInstance).InterfaceTwoMethod();
Can anyone recommend a design pattern or exact syntax that would make something like this work?
Inside the MergeFactory, I'm picturing something like this going on:
MergeFactory<Iface1, Iface2>() :
where Iface1: IMergeable, Iface2: IMergeable
{
IMergeable instance = Iface1Factory.CreateIface1Instance();
instance.Merge(Iface2Factory.CreateIface2Instance());
}
C is not an Object Oriented language. Inheritance is a property of Object Oriented languages. There is no Compiler-level support for inheritance in C.
The bitwise OR assignment operator ( |= ) uses the binary representation of both operands, does a bitwise OR operation on them and assigns the result to the variable.
In C programming language, %d and %i are format specifiers as where %d specifies the type of variable as decimal and %i specifies the type as integer. In usage terms, there is no difference in printf() function output while printing a number using %d or %i but using scanf the difference occurs.
Sounds like a job for the Adapter Pattern
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Create adapter and place a request
MergeFactoryTarget target = new Adapter<AdapteeA, AdapteeB>();
target.InterfaceACall();
target.InterfaceBCall();
}
}
/// <summary>
/// The 'Target' class
/// </summary>
public class MergeFactoryTarget
{
public virtual void InterfaceACall()
{
Console.WriteLine("Called Interface A Function()");
}
public virtual void InterfaceBCall()
{
Console.WriteLine("Called Interface B Function()");
}
}
/// <summary>
/// The 'Adapter' class
/// </summary>
class Adapter<AdapteeType1, AdapteeType2> : MergeFactoryTarget
where AdapteeType1 : IAdapteeA
where AdapteeType2 : IAdapteeB
{
private AdapteeType1 _adapteeA = Activator.CreateInstance<AdapteeType1>();
private AdapteeType2 _adapteeB = Activator.CreateInstance<AdapteeType2>();
public override void InterfaceACall()
{
_adapteeA.InterfaceOneMethod();
}
public override void InterfaceBCall()
{
_adapteeB.InterfaceTwoMethod();
}
}
/// <summary>
/// AdapteeA Interface
/// </summary>
interface IAdapteeA
{
void InterfaceOneMethod();
}
/// <summary>
/// AdapteeB Interface
/// </summary>
interface IAdapteeB
{
void InterfaceTwoMethod();
}
/// <summary>
/// The 'AdapteeA' class
/// </summary>
class AdapteeA : IAdapteeA
{
public void InterfaceOneMethod()
{
Console.WriteLine("Called InterfaceOneMethod()");
}
}
/// <summary>
/// The 'AdapteeB' class
/// </summary>
class AdapteeB : IAdapteeB
{
public void InterfaceTwoMethod()
{
Console.WriteLine("Called InterfaceTwoMethod()");
}
}
As pointless as this construct might be, for some reason it intrigued me and I quickly mocked up a Castle DynamicProxy implementation for creating objects that bundles together multiple interfaces.
The mixin factory provides two methods:
object CreateMixin(params object[] objects)
Returns an object that implements any number of interfaces. In order to get to the implemented interface you must cast the returned object to that interface.
TMixin CreateMixin<TMixin, T1, T2>(T1 obj1, T2 obj2)
Returns an interface that implements the other two interfaces to achieve strong typing. That combining interface must exist at compile time.
Here are the objects:
public interface ICat {
void Meow();
int Age { get; set; }
}
public interface IDog {
void Bark();
int Weight { get; set; }
}
public interface IMouse {
void Squeek();
}
public interface ICatDog : ICat, IDog {
}
public interface ICatDogMouse : ICat, IDog, IMouse {
}
public class Mouse : IMouse {
#region IMouse Members
public void Squeek() {
Console.WriteLine("Squeek squeek");
}
#endregion
}
public class Cat : ICat {
#region ICat Members
public void Meow() {
Console.WriteLine("Meow");
}
public int Age {
get;
set;
}
#endregion
}
public class Dog : IDog {
#region IDog Members
public void Bark() {
Console.WriteLine("Woof");
}
public int Weight {
get;
set;
}
#endregion
}
Take note of ICatDog
interface.I thought that it would be pretty cool if the dynamic proxy returns something that is strongly typed and can be used where either interface is accepted. This interface will need to be defined at compile time if strong typing is indeed desireable. Now for the factory:
using Castle.DynamicProxy;
public class MixinFactory {
/// <summary>
/// Creates a mixin by comining all the interfaces implemented by objects array.
/// </summary>
/// <param name="objects">The objects to combine into one instance.</param>
/// <returns></returns>
public static object CreateMixin(params object[] objects) {
ProxyGenerator generator = new ProxyGenerator();
ProxyGenerationOptions options = new ProxyGenerationOptions();
objects.ToList().ForEach(obj => options.AddMixinInstance(obj));
return generator.CreateClassProxy<object>(options);
}
/// <summary>
/// Creates a dynamic proxy of type TMixin. Members that called through this interface will be delegated to the first matched instance from the objects array
/// It is up to the caller to make sure that objects parameter contains instances of all interfaces that TMixin implements
/// </summary>
/// <typeparam name="TMixin">The type of the mixin to return.</typeparam>
/// <param name="objects">The objects that will be mixed in.</param>
/// <returns>An instance of TMixin.</returns>
public static TMixin CreateMixin<TMixin>(params object[] objects)
where TMixin : class {
if(objects.Any(o => o == null))
throw new ArgumentNullException("All mixins should be non-null");
ProxyGenerator generator = new ProxyGenerator();
ProxyGenerationOptions options = new ProxyGenerationOptions();
options.Selector = new MixinSelector();
return generator.CreateInterfaceProxyWithoutTarget<TMixin>(options, objects.Select(o => new MixinInterceptor(o)).ToArray());
}
}
public class MixinInterceptor : IInterceptor {
private object m_Instance;
public MixinInterceptor(object obj1) {
this.m_Instance = obj1;
}
public Type ObjectType {
get {
return m_Instance.GetType();
}
}
#region IInterceptor Members
public void Intercept(IInvocation invocation) {
invocation.ReturnValue = invocation.Method.Invoke(m_Instance, invocation.Arguments);
}
#endregion
}
public class MixinSelector : IInterceptorSelector{
#region IInterceptorSelector Members
public IInterceptor[] SelectInterceptors(Type type, System.Reflection.MethodInfo method, IInterceptor[] interceptors) {
var matched = interceptors
.OfType<MixinInterceptor>()
.Where(mi => method.DeclaringType.IsAssignableFrom(mi.ObjectType))
.ToArray();
if(matched.Length == 0)
throw new InvalidOperationException("Cannot match method " + method.Name + "on type " + method.DeclaringType.FullName + ". No interceptor for this type is defined");
return matched;
}
#endregion
}
Usage is best explained in these unit tests. As you can see the second method returns a type safe interface that seemlessly bundles any number of interfaces.
[TestMethod]
public void CreatedMixinShouldntThrow() {
ICat obj1 = new Cat();
IDog obj2 = new Dog();
var actual = MixinFactory.CreateMixin(obj1, obj2);
((IDog)actual).Bark();
var weight = ((IDog)actual).Weight;
((ICat)actual).Meow();
var age = ((ICat)actual).Age;
}
[TestMethod]
public void CreatedGeneric3MixinShouldntThrow() {
ICat obj1 = new Cat();
IDog obj2 = new Dog();
IMouse obj3 = new Mouse();
var actual = MixinFactory.CreateMixin<ICatDogMouse>(obj1, obj2, obj3);
actual.Bark();
var weight = actual.Weight;
actual.Meow();
var age = actual.Age;
actual.Squeek();
}
I have blogged about this in more detail and provided source and tests. You can find it here.
If you're using .NET 4.0 implement IDynamicMetaObjectProvider on a proxy class that takes instances of classes against all the interfaces in a constructor
http://msdn.microsoft.com/en-us/vcsharp/ff800651.aspx
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With