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

时间:2015-05-15 10:19:34

标签: c# expression-trees

假设我有以下界面和两个实现。

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方法来“配置”代理。这基本上是一个列表或字典,每个项目应该是方法和类型。应该在使用表达式树生成代理时检查要使用的实现。

所以用

Talk,DutchPerson 午餐,EnglishPerson

GetProxy方法将返回(伪代码)

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

       return DutchPerson.Talk()
    }

    public Lunch() {

       EnglishPerson.Lunch()
    }
}

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

所以我以错误的方式看待它,使用Expression树甚至是合理可行的。我正在使用.NET 4.5.1。

2 个答案:

答案 0 :(得分:2)

通过System.Reflection.Emit + Expression树来完成它非常/非常复杂......但如果你有一个不变的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;
}

在运行时创建代理类的唯一好处是:

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

  • 对于MergedInstance类中的每个方法,您可以使用少于一个引用(取决于配置,您需要的引用数在所有方法使用的单个引用之间是可变的,1对于每种方法,所以最大值是相同的,它是最小的变化)

答案 1 :(得分:1)

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

如果性能真的很关键,我仍然会尝试编写而不是动态生成类,但是你可以尝试使用Reflection.Emit方式(如@xantos建议的那样),这可以通过更快的运行时间来完成相同的操作。生成类(本身并不快)。祝你好运