Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible in c# to make a factory that merges interfaces?

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());
}
like image 371
djmc Avatar asked Aug 05 '10 02:08

djmc


People also ask

Is inheritance is possible in C?

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.

What does |= mean 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.

What does %d do in C?

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.


3 Answers

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()");
      }
   }
like image 92
SwDevMan81 Avatar answered Oct 07 '22 20:10

SwDevMan81


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.

like image 29
Igor Zevaka Avatar answered Oct 07 '22 20:10

Igor Zevaka


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

like image 25
Muhammad Hasan Khan Avatar answered Oct 07 '22 20:10

Muhammad Hasan Khan