传递给构造函数的Func对象最终为null

时间:2015-03-11 15:30:41

标签: c#

我有一个Singleton对象,包含一个匿名委托作为属性,我想让它访问我程序中的其他类。

public sealed class HeuristicManager
{
    public Func<IMap, Owner, float> GetScore { get; protected set; }
    protected HeuristicDictionary weightedRules;

    private static readonly Lazy<HeuristicManager> lazy = new Lazy<HeuristicManager>(() => new HeuristicManager());
    public static HeuristicManager Instance { get { return lazy.Value; } }
    private HeuristicManager()
    {
        GetScore = (IMap map, Owner player) =>
        {
            float score = 0;
            foreach (var weightedRule in weightedRules)
                score += weightedRule.Key.EvaluateScore(map, player) + weightedRule.Value;
            return score / weightedRules.TotalWeight;
        };
    }
}

有些初始化失踪了,但你明白了。我使用Singleton而不是静态类,因为我想存储我的GetScore函数的先前结果以供重用。

我在我的程序中的其他地方创建了一个对象的实例,它将GetScore函数作为参数,如下所示:

public override IEnumerable<TreeNode> ComputeNodeChildren()
{
    var mapPerNode = generateMapPerNode();
    foreach (var map in mapPerNode)
        yield return new TreeNode(map.Item1, map.Item2, HeuristicManager.Instance.GetScore);
}

我的问题是,当我直接从Singleton调用GetScore时,它运行得很好,但是一旦它被传递给TreeNode实例,它就会变为null并且我的程序崩溃,因为我正在调用a null函数。

TreeNode构造函数如下:

public TreeNode(IMap value, List<Move> moveList, Func<IMap, Owner, float> heuristic)
{
    Map = value;
    MoveList = moveList;
    this.heuristic = heuristic; // Both are null
    Heuristic = player => this.heuristic(Map, player); 
    ChildrenHashes = new List<int>();
}

我一定错过了一些东西,我很高兴能够对此有所了解。

谢谢!

1 个答案:

答案 0 :(得分:0)

可能也可以解决您的问题的次要优化:在循环外提升属性访问权限(包括自定义getter,Lazy<T>访问权限,然后是自动支持):

public override IEnumerable<TreeNode> ComputeNodeChildren()
{
    var mapPerNode = generateMapPerNode();
    var scoreFn = HeuristicManager.Instance.GetScore;
    foreach (var map in mapPerNode)
        yield return new TreeNode(map.Item1, map.Item2, scoreFn);
}

也许更好

private IEnumerable<TreeNode> ComputeNodeChildrenImpl(TypeA mapPerNode, Func<IMap, Owner, float> scoreFn)
{
    foreach (var map in mapPerNode)
        yield return new TreeNode(map.Item1, map.Item2, scoreFn);
}

public override IEnumerable<TreeNode> ComputeNodeChildren()
{
    var mapPerNode = generateMapPerNode();
    var scoreFn = HeuristicManager.Instance.GetScore;
    return ComputeNodeChildrenImpl(mapPerNode, scoreFn);
}

每当方法包含yield时,该方法中的所有代码都会延迟执行。如果显示参数验证和初始化,调试和处理错误通常会容易得多,如图所示。

请注意,第二个版本也可以使用LINQ的Select实现编写,没有明确的帮助:

public override IEnumerable<TreeNode> ComputeNodeChildren()
{
    var scoreFn = HeuristicManager.Instance.GetScore;
    return generateMapPerNode().Select(map => new TreeNode(map.Item1,
                                                           map.Item2, scoreFn));
}