是否可以在c#中创建一个合并接口的工厂? [英] Is it possible in c# to make a factory that merges interfaces?

查看:104
本文介绍了是否可以在c#中创建一个合并接口的工厂?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

((InterfaceOne)mergedInstance).InterfaceOneMethod();
((InterfaceTwo)mergedInstance).InterfaceTwoMethod();

任何人都可以推荐使用这样的设计模式或精确的语法?



在MergeFactory内部,我正在画这样的事情:

  MergeFactory< ; Iface1,Iface2>():
其中Iface1:IMergeable,Iface2:IMergeable
{
IMergeable instance = Iface1Factory.CreateIface1Instance();
instance.Merge(Iface2Factory.CreateIface2Instance());
}


解决方案

由于某种原因,它引起了我的兴趣,我很快就嘲弄了一个Castle DynamicProxy实现,用于创建捆绑在一起的多个接口的对象。



mixin工厂提供了两种方法: p>

对象CreateMixin(params object [] objects)



返回一个实现任意数量接口的对象。为了获得实现的接口,您必须将返回的对象转换到该接口。



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



返回实现其他两个接口以实现强类型的接口。该组合界面必须在编译时存在。



以下是对象:

  public interface ICat {
void Meow();
int年龄{get;组; }
}

public interface IDog {
void Bark();
int重量{get;组;
}

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;
设置;
}

#endregion
}

public class Dog:IDog {
#region IDog Members

public void Bark(){
Console.WriteLine(Woof);
}

public int重量{
get;
设置;
}

#endregion
}

注意 ICatDog interface.I以为如果动态代理返回强类型的东西,并且可以在接受任一接口的地方使用,那将是非常好的。如果强化打字确实是需要的,这个接口将需要在编译时进行定义。现在出厂:

 使用Castle.DynamicProxy; 

public class MixinFactory {
///< summary>
///通过汇总由objects数组实现的所有接口创建一个mixin。
///< / summary>
///< param name =objects>要组合成一个实例的对象。< / 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>
///创建类型为TMixin的动态代理。通过此接口调用的成员将被委派给对象数组中的第一个匹配的实例
///由调用者确定objects参数包含TMixin实现的所有接口的实例
/ //< / summary>
///< typeparam name =TMixin>要返回的mixin的类型。< / typeparam>
///< param name =objects>将要混合的对象。< / param>
///< returns> TMixin的实例。< / returns>
public static TMixin CreateMixin< TMixin>(params object [] objects)
其中TMixin:class {
if(objects.Any(o => o == null))
抛出新的ArgumentNullException(所有mixins应该是非空);

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成员

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(Can not match method+ method.Name +on type+ method.DeclaringType.FullName +。此类型的拦截器不是定义);
返回匹配;
}

#endregion
}

使用方法在这些单元测试中最好的解释。您可以看到第二种方法返回一个类似的安全界面,它似乎捆绑了许多接口。

  [TestMethod] 
public void CreatedMixinShouldntThrow(){
ICat obj1 = new Cat();
IDog obj2 = new Dog();

var actual = MixinFactory.CreateMixin(obj1,obj2);
((IDog)实际).Bark();
var weight =((IDog)actual).Weight;
((ICat)实际).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();
}

我更详细地介绍了这一点,并提供了源代码和测试。你可以找到它 here


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());
}

解决方案

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.

这篇关于是否可以在c#中创建一个合并接口的工厂?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆