我有一个Player类和一个Stat类。 Player类有一个List属性,其中PlayerStat具有List和XP属性。我认为我的设计存在缺陷,因为我在做一些我觉得应该很容易的事情。我想列出所有玩家及其所有统计数据的XP。下面是类和GetCompletePlayerStats方法的更多细节,这是我真正不喜欢的。我基本上需要为玩家的所有统计数据列出XP,如果玩家没有统计数据,那么它的XP应为零。任何设计帮助/建议将不胜感激。
public class Stat : EntityBase{
public virtual string Name { get; set; }
public virtual UnitOfMeasure Unit { get; set; }
public virtual int UnitXP { get; set; }
}
public class Player : EntityBase{
public virtual string Name { get; set; }
public virtual IList<PlayerStat> PlayerStats { get; set; }
public virtual List<PlayerStat> GetCompletePlayerStats(IQueryable<Stat> stats)
{
var allStats = new List<PlayerStat>();
var playerStatIds = PlayerStats.Select(ps => ps.PlayerStatistic.Id).ToList();
if (playerStatIds.Count == 0)
{
allStats.AddRange(stats.Select(stat => new PlayerStat() {PlayerStatistic = stat, XP = 0}));
}
else
{
var zeroStats = stats.Where(s => !playerStatIds.Contains(s.Id)).ToList();
allStats.AddRange(zeroStats.Select(zeroStat => new PlayerStat() {PlayerStatistic = zeroStat, XP = 0}));
allStats.AddRange(PlayerStats);
}
return allStats;
}
}
public class PlayerStat : EntityBase{
public virtual Stat PlayerStatistic { get; set; }
public virtual double XP { get; set; }
}
答案 0 :(得分:0)
我不得不承认,到目前为止,我还没有真正看到你班级设计的一个主要缺点。当然,我对大局以及你的游戏设计没有任何见解,因为这只是它的一小部分。
但是,你说你不喜欢GetCompletePlayerStats
。我必须多次阅读才能理解你在这里要做的事情。如果我看到了这一点,您只想返回与每个给定PlayerStat
对象相对应的Stat
对象。我猜Stat
有一个Id
字段(您在方法中使用它)来比较其中两个字段的语义相等。
鉴于我到目前为止做出了正确的假设(不幸的是,你没有提供太多信息),该方法可以简化为:
public virtual IEnumerable<PlayerStat> GetCompletePlayerStats(IEnumerable<Stat> stats)
{
foreach(Stat stat in stats)
yield return PlayerStats.FirstOrDefault(s => stat.Id == s.PlayerStatistic.Id) ??
new PlayerStat() {PlayerStatistic = stat, XP = 0};
yield break;
}
这里的方法不需要IQueryable
而是IEnumerable
来通过foreach
循环进行迭代,如果存在,则会产生相应的PlayerStats
对象,或者创建一个XP设置为0的新的(否则空归合运算符??
在这些情况下非常有用)。
希望有所帮助!
答案 1 :(得分:0)
使用现有设计,这种方法可以简化:
public virtual IList<PlayerStat> GetCompletePlayerStats(IEnumerable<Stat> stats)
{
// build a dictionary of existing stats by ID to facilitate
// the join with requested stats (effectively doing a hash join)
var playerStatsById = PlayerStats.ToDictionary(ps => ps.PlayerStatistic.Id);
// for each requested stat, return either the corresponding player stat
// or a zero stat if one isn't found, maintaining the original order of stats
return stats
.Select(s => playerStatsById.ContainsKey(s.Id) ?
playerStatsById[s.Id] :
new PlayerStat { PlayerStatistic = s, XP = 0 })
.ToList();
}
请注意,由于这实际上是一个外连接操作(您将stats
与PlayerStats
连接,但您还需要将不匹配产生为零)您也可以使用LINQ来实现GroupJoin()操作,虽然我怀疑它的可读性会低得多。
关于你的设计让我烦恼的是名字含糊不清,例如你有PlayerStat
类和PlayerStatistic
属性,它们意味着微妙的不同;考虑以不同的方式命名,事情可能看起来更好;事实上,对于任何情况,这可能是我能给你的最佳设计建议:))