使用表达式树通过代理现有实现来实现接口

Use Expression tree to implement interface by proxying existing implementation

假设我有以下接口和两个实现。

public interface IPerson
{
    string Talk();
    void Lunch();

}

public class DutchPerson : IPerson
{
    public string Talk()
    {
        return "Ik spreek Nederlands.";
    }

    public void Lunch()
    {
        EatBroodjeKroket();
    }

    private void EatBroodjeKroket()
    {

    }
}

public class EnglishPerson : IPerson
{
    public string Talk()
    {
        return "I speak English.";
    }

    public void Lunch()
    {
        EatFishAndChips();
    }

    private void EatFishAndChips()
    {

    }
}




public class ImplementationBuilder<T>
{

    private Dictionary<Type, IPerson> _instances;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="instances">Instances that will be used in proxy</param>
    public ImplementationBuilder(Dictionary<Type, IPerson> instances)
    {
        _instances = instances;
    }

    public void Setup()
    {

    }

    /// <summary>
    /// this should return the generated instance
    /// </summary>
    public IPerson GetProxy()
    {


        return null;
    }
}

我想做的是使用表达式树创建一个新的实现,并混合和匹配来自两个(或更多)实现的方法。基本上我想创建一个实现 IPerson 的代理。所以我传入了将要使用的实例,我想使用 Setup 方法来 "configure" 代理。这基本上是一个列表或字典,每个项目都应该是方法和类型。在使用表达式树生成代理时应该检查要使用的实现。

所以

说说,DutchPerson 午餐,英语人

GetProxy 方法将 return(伪代码)

public class MergedInstance : IPerson
{
    public void Talk() {

       return DutchPerson.Talk()
    }

    public Lunch() {

       EnglishPerson.Lunch()
    }
}

我主要想要这个是因为代理的实现包含很多方法,我希望能够使用功能标志在实现之间切换。

所以我是不是看错了,使用表达式树这是否合理可行。我正在使用 .NET 4.5.1。

通过 System.Reflection.Emit + Expression 树来实现是 quite/very 复杂的......但是如果你有一个不变的 IPerson 你可以:

public class MergedInstance : IPerson
{
    public IPerson TalkIPerson { get; set; }
    public IPerson LunchIPerson { get; set; }

    public void Talk() 
    {
       TalkIPerson.Talk();
    }

    public Lunch() {
       LunchIPerson.Lunch();
    }
}

等等

那么你的GetProxy可以

public IPerson GetProxy()
{
    var merged = MergedInstance();

    merged.TalkIPerson = ...
    merged.LunchIPerson = ...

    return merged;
}

在运行时创建代理 class 的唯一优点是:

  • 您可以使用任何界面(因此它可以与 IPersonIAnimal、...一起使用),在运行时选择。逻辑可以通过其他方法 and/or 的委托注入,由 XML 或其他配置对象

  • 读取
  • 您的 MergedInstance class 中的每个方法可以有少于一个引用(根据配置,您需要的引用数量在单个所有方法使用一个,每个方法使用一个,所以最大值相同,变化的是最小值)

我不认为表情树是你的朋友。阅读运行时编织(代理)。一个非常容易理解和使用的框架是例如 Castle DynamicProxy (http://www.castleproject.org/projects/dynamicproxy/)。阅读一些 howtos,你会发现自己很惊讶。

如果性能真的很关键,我仍然会尝试组合而不是动态生成 类,但是您可以尝试 Reflection.Emit 方式(正如@xantos 所建议的),它可以一旦 类 生成(它本身并不快),就可以用更快的运行时间完成同样的事情。祝你好运