【问题标题】:Proxying meta-interfaces with Castle Dynamic Proxy使用 Castle Dynamic Proxy 代理元接口
【发布时间】:2013-11-08 06:03:33
【问题描述】:

我有一个关于 Castle Dynamic Proxy 的问题(我使用 Castle Windsor 作为 IoC 框架已经有一段时间了,但从未直接使用过动态代理)。

我有几个描述类能力的接口。例如:

public interface IBeatScissors 
{
    void BeatScissors();
}

public interface IBeatRock 
{
    void BeatRock();
}

public interface IBeatPaper 
{
    void BeatPaper();
}

public interface IBeatSpock 
{
    void BeatSpock();
}

public interface IBeatLizard 
{
    void BeatLizard();
}

下面是实现它们的类:

public abstract class Rock : Weapon, IBeatScissors, IBeatLizard
{
    public abstract void BeatScissors();
    public abstract void BeatLizard();
}

public abstract class Paper : Weapon, IBeatRock, IBeatSpock
{
    public abstract void BeatRock();
    public abstract void BeatSpock();
}

public abstract class Scissors : Weapon, IBeatPaper, IBeatLizard
{
    public abstract void BeatPaper();
    public abstract void BeatLizard();
}

public abstract class Lizard : Weapon, IBeatPaper, IBeatSpock
{
    public abstract void BeatPaper();
    public abstract void BeatSpock();
}

public abstract class Spock : Weapon, IBeatScissors, IBeatRock
{
    public abstract void BeatScissors();
    public abstract void BeatRock();
}

此外,我还有更多结合上述功能的接口(这些是我所说的“元接口”):

public interface IBeatScissorsAndLizard : IBeatScissors, IBeatLizard
{
}

public interface IBeatRockAndSpock : IBeatRock, IBeatSpock
{
}

public interface IBeatPaperAndLizard : IBeatPaper, IBeatLizard
{
}

public interface IBeatPaperAndSpock : IBeatPaper, IBeatSpock
{
}

public interface IBeatScissorsAndRock : IBeatScissors, IBeatRock
{
}

现在我想将实现类“强制转换”(或其他)到这些元接口,并将它们传递给使用方法:

public abstract class Game
{
    public void BeatScissorsAndLizard(Weapon weapon)
    {
        var w = weapon.Duck<IBeatScissorsAndLizard>();
        if(w == null)
           throw new Exception("You can't win!");
        w.BeatScissors();
        w.BeatLizard();
    }
    public abstract void BeatRockAndSpock(Weapon weapon);
    public abstract void BeatPaperAndLizard(Weapon weapon);
    public abstract void BeatPaperAndSpock(Weapon weapon);
    public abstract void BeatScissorsAndRock(Weapon weapon);
}

在我的实际应用程序中,我不能简单地让实现类也实现元接口,因为可能的组合数量太多了 - 这只是一个示例!

我过去一直在使用Cs-Script,它有一个名为“AlignToInterface”的扩展方法,它几乎可以实现我想要实现的目标,例如:

Rock rock = new Rock();
IBeatScissorsAndLizard beatem = rock.AlignToInterface<IBeatScissorsAndLizard>();

不幸的是,我不能在这里使用它,因为它抱怨元接口没有实现派生方法。我认为这是一个错误 - 一个接口怎么可能实现另一个接口?!?!

现在,我的问题是,是否(如果是,如何)使用 Castle Dynamic 代理可以完成类似操作?

任何帮助表示赞赏!

更新:编辑了消费示例。

【问题讨论】:

    标签: c# castle-dynamicproxy


    【解决方案1】:

    如果你坚持,你可以使用 Castle。您正在寻找的功能称为duck typing。基本思想是,给定一个类与某个接口具有相同的公共 API,或者该接口的 API 是该类提供的 API 的子集,您可以通过接口引用使用该类的实例。

    您可以找到使用 Castle Windsor herehere 实现该功能的示例。据我了解,这两种实现都只是概念证明。另一个支持开箱即用的鸭式输入的 DI 框架是 LinFu,但看起来它的维护早就被放弃了。

    另一个问题是你是否需要鸭子打字。鉴于您拥有每个接口的实现,您可以通过以下方式使用泛型类型参数的约束:

    public abstract class Game
    {
        public abstract void BeatScissorsAndLizard<T>(T weapon)
            where T : IBeatScissors, IBeatLizard;
    
        public abstract void BeatPaperAndLizard<T>(T weapon)
            where T : IBeatPaper, IBeatLizard;
    
        //more here...
    }
    

    然后像这样使用它(假设你的类不是抽象的):

    game.BeatPaperAndLizard(new Scissors());
    
    //this does not compile:
    //game.BeatScissorsAndLizard(new Spock()); 
    
    game.BeatScissorsAndLizard(new Rock());
    

    【讨论】:

    • 谢谢@galenus,这应该让我工作。我想坚持使用 Castle,因为我使用 Windsor 作为 IoC 框架,所以我已经加载了 Castle.Core 程序集。您发布的第一个示例作为起点似乎很简单。我不能使用您提供的替代方案,因为我在通用实用程序程序集中执行此操作,并且我“躲避”的对象是从外部传递的(甚至可能作为类型对象),所以我无法控制它。我只是想确保该对象实现了我在内部使用的所有接口......
    • 可能我什么都没有,但是使用类型参数约束和指定显式接口有什么区别?一旦定义了约束,在实现所有必需的接口之前,任何东西都不能进入方法。在duck 类型的情况下,您还必须duck 实例,这具有相当大的性能成本。 Duck 类型适用于您想要将外部提供的某些类作为您在内部定义的接口进行屏蔽的情况,例如将某些框架类型“转换”为用户定义的类型。
    • 是的,你是对的,这没有多大意义。我已经编辑了这些示例,使其更加真实。武器确实是外部提供的,所以我无法确保它们会实现所需的接口......无论如何,谢谢,我对你提供的解决方案很好!
    猜你喜欢
    • 2011-09-05
    • 2012-06-01
    • 2011-10-24
    • 2011-10-03
    • 2018-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    相关资源
    最近更新 更多