构建彼此需要的代表

时间:2015-01-21 20:37:18

标签: c# .net delegates

我试图定义两个相互引用的代表,但我不确定最有效的方法是什么。我希望能够在没有任何隐式捕获的闭包的情况下完成它。

我有一些看起来有点像这样的东西:

Func<A, C> AtoC = null;
Func<B, C> BtoC = delegate(B b_in)
{
   //... uses some variables scoped to the outer method
   return b_in.getC() ?? AtoC( b_in.getA() );
}
AtoC  = delegate(A a_in)
{
   //... uses some variables scoped to the outer method
   return a_in.getC() ?? BtoC( a_in.getB() );
}

C final = AtoC(someA);

当然,真正的逻辑更复杂,但正如你可以看到每个委托引用另一个,并且隐式捕获了闭包。

我希望能够通过让工厂使用范围为外部方法的&#34;变量创建它们来更明确地构建这些代理&#34;:

Func<A, C> AtoC = null;
Func<B, C> BtoC = MakeFunctionBtoC(someVariables, AtoC)
Func<A, C> AtoC = MakeFunctionAtoC(someVariables, BtoC)
C final = AtoC(someA);

//Elsewhere...
Func<B, C> MakeFunctionBtoC(someVariables, Func<A, C> AtoC)
{
    return delegate(B b_in)
    {
       //... uses someVariables
       return b_in.getC() ?? AtoC( b_in.getA() );
    }
}

因此明确地捕捉了一些变量&#39;我希望用它构建委托。问题是使用此方法,传递给AtoC工厂的函数BtoC在调用方法时为null,并且复制了该null值,因此即使稍后调用委托也是如此,函数AtoC永远不会被定义(就像前一种情况一样)。

是否有一种方法可以让代理人使用工厂方法,同时让他们彼此依赖?

1 个答案:

答案 0 :(得分:1)

如果您希望将这两种方法的实际业务逻辑重构为自己的命名方法,那么您肯定可以这样做。然后,您可以使用一个匿名方法来关闭代理,以实际调用该命名方法:

Func<A, C> AtoC = null;
Func<B, C> BtoC = b => ConvertBToC(someVariables, AtoC);
AtoC = a => ConvertAtoC(someVariables, BtoC);
C final = AtoC(someA);

现在,您可以将ConvertBToC编写为可以接受Func<A, C>作为参数的单独命名方法。它允许将每个对象转换为另一个对象,以便通过它们的循环引用与两个代表的连接分开。当然,它根本不能避免使用闭包;它只是让它们与业务逻辑分开。

如果你想真正避免使用闭包,那么你的问题在技术上要求:

您可以添加另一个间接层;创建一个可变引用类型,其中包含函数可以引用的相关委托类型的字段:

public class Wrapper<T>
{
    public T Value { get; set; }
}

Func<B, C> MakeFunctionBtoC(someVariables, Wrapper<Func<A, C>> AtoC)
{
    return delegate(B b_in)
    {
       //... uses someVariables
       return b_in.getC() ?? AtoC.Value( b_in.getA() );
    }
}

当然,正如你在第一个解决方案中所做的那样,这是道德等同于你使用闭包时所发生的事情(我觉得需要指出你的第二个解决方案也是关闭变量,它们是只是方法参数而不是局部变量。)

我不认为这比你原来的解决方案更优越,这似乎是解决这个问题的最好方法。

你有另一个选择是有效地执行编译器在看到闭包时会做的重构,即创建一个新类型,创建一个可变字段来表示关闭的变量,然后使用它而不是到处都是封闭的变量。你只是通过这样做而不是使用闭包来真正使代码变得更复杂。