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

本文关键字:实现 代理 接口 表达式 | 更新日期: 2023-09-27 17:49:18

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

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方法来"配置"代理。这基本上是一个List或Dictionary,每一项都应该是Method和Type。在使用表达式树生成代理时,应该检查要使用的实现。

说话,DutchPerson午餐,EnglishPerson

GetProxy方法将返回(伪代码)

public class MergedInstance : IPerson
{
    public void Talk() {
       return DutchPerson.Talk()
    }
    public Lunch() {
       EnglishPerson.Lunch()
    }
}

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

所以我看它在错误的方式,这甚至是合理可行的使用表达式树。我使用的是。net 4.5.1

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

通过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;
}

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

  • 你可以使用任何接口(所以它可以使用IPerson, IAnimal,…),选择在运行时。逻辑可以通过其他方法的委托注入和/或由XML或其他配置对象读取

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

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

如果性能真的很关键,我仍然会尝试组合而不是动态地生成类,但是您可以尝试反射。Emit方法(如@xantos所建议的),可以在生成类后更快地运行时完成相同的工作(这本身并不快)。祝你好运