Is it possible to create a factory in C # that integrates interfaces?

var mergedInstance = MergeFactory<InterfaceOne, InterfaceTwo>(); ((InterfaceOne)mergedInstance).InterfaceOneMethod(); ((InterfaceTwo)mergedInstance).InterfaceTwoMethod(); 

Can anyone recommend a design template or exact syntax that would do something like this work?

Inside MergeFactory, I present something like this:

 MergeFactory<Iface1, Iface2>() : where Iface1: IMergeable, Iface2: IMergeable { IMergeable instance = Iface1Factory.CreateIface1Instance(); instance.Merge(Iface2Factory.CreateIface2Instance()); } 
+6
generics design c # design-patterns
source share
5 answers

How pointless, since this design could be, for some reason, it intrigued me, and I quickly mocked the implementation of Castle DynamicProxy to create objects that combine multiple interfaces.

Mixin factory provides two methods:

object CreateMixin(params object[] objects)

Returns an object that implements any number of interfaces. To go to the implemented interface, you must pass the returned object to this interface.

TMixin CreateMixin<TMixin, T1, T2>(T1 obj1, T2 obj2)

Returns an interface that implements two other interfaces to achieve strong typing. This 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 } 

Pay attention to the ICatDog interface. I thought it would be great if the dynamic proxy returns something strongly typed and can be used where any interface is accepted. This interface will need to be determined at compile time if strong typing is really desired. 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 secure interface of the type that without any visibility binds 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 talked about this in more detail and provided the source and tests. You can find it here .

+4
source share

Sounds like a job for adapter template

  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()"); } } 
+5
source share

If you are using .NET 4.0, implement IDynamicMetaObjectProvider in a proxy class that accepts class instances against all interfaces in the constructor

http://msdn.microsoft.com/en-us/vcsharp/ff800651.aspx

+4
source share

Give up Castle DynamicProxy , which uses IL Emit to create proxies on the fly. You can issue a proxy server that implements two interfaces and then delegates calls to two encapsulated instances. If you're curious, this is actually not too difficult to implement, but there are some angular cases to consider, and the IL Emit classes do not particularly forgive mistakes (which makes them difficult to study).

+3
source share

Hassan's answer (IDynamicMetaObjectProvider) is a good bet if you're on .NET 4.0.

You can also look at RealProxy / DynamicProxy that were with .NET 1.0. I think libraries like Moq fake individual interfaces at a time, and I think they also allow you to intercept throws, which should allow you to accomplish what you are looking for. Here's an article about TransparentProxy , and here's the MSDN documentation for RealProxy and RealProxy.GetTransparentProxy .

+2
source share

All Articles