我有一个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>();
}
我一定错过了一些东西,我很高兴能够对此有所了解。
谢谢!
答案 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));
}