C# 类设计问题:列表的并集<;ChildStat>;和AllStats

C# 类设计问题:列表的并集<;ChildStat>;和AllStats,c#,linq,class,C#,Linq,Class,我有一个玩家类和一个统计类。Player类有一个List属性,其中PlayerStat有一个List和XP属性。我认为我的设计是有缺陷的,因为我在做我认为应该简单的事情时遇到了困难。我想列出所有球员和他们的XP的所有统计数据。下面是类和GetCompletePlayerStats方法的更多细节,这是我真正不喜欢的。我基本上需要列出一个玩家所有属性的XP,如果玩家没有属性,那么它的XP应该为零。如有任何设计帮助/建议,将不胜感激 public class Stat : EntityBase{

我有一个玩家类和一个统计类。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; }
}
公共类统计:EntityBase{
公共虚拟字符串名称{get;set;}
公共虚拟度量单位{get;set;}
公共虚拟int UnitXP{get;set;}
}
公共类播放器:EntityBase{
公共虚拟字符串名称{get;set;}
公共虚拟IList PlayerStats{get;set;}
公共虚拟列表GetCompletePlayerStats(IQueryable统计信息)
{
var allStats=新列表();
var playerStatIds=PlayerStats.Select(ps=>ps.PlayerStatistic.Id).ToList();
如果(playerStatIds.Count==0)
{
AddRange(stats.Select(stat=>newplayerstat(){PlayerStatistic=stat,XP=0}));
}
其他的
{
var zeroStats=stats.Where(s=>!playerStatIds.Contains(s.Id)).ToList();
AddRange(zeroStats.Select(zeroStat=>newplayerstat(){PlayerStatistic=zeroStat,XP=0}));
allStats.AddRange(PlayerStats);
}
返回所有统计信息;
}
}
公共类PlayerStat:EntityBase{
公共虚拟统计PlayerStatistic{get;set;}
公共虚拟双XP{get;set;}
}

我必须承认,到目前为止,我并不认为你们的课堂设计有什么大的缺陷。当然,我对更大的图景以及你的游戏是如何设计的没有任何见解,因为这只是其中的一小部分

但是,您说您不喜欢的是
GetCompletePlayerStats
。我读了好几遍才明白你想在这里做什么。如果我看对了,您只需要返回一个与每个给定的
Stat
对象对应的
PlayerStat
对象。我猜
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;
}
公共虚拟IEnumerable GetCompletePlayerStats(IEnumerable stats)
{
foreach(stats中的Stat)
返回PlayerStats.FirstOrDefault(s=>stat.Id==s.PlayerStatistic.Id)??
新的PlayerStat(){PlayerStatistic=stat,XP=0};
屈服断裂;
}
这里的这个方法不需要
IQueryable
,而是需要
IEnumerable
通过
foreach
循环进行迭代,如果存在相应的
PlayerStats
对象,或者创建一个XP设置为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;
}
公共虚拟IEnumerable GetCompletePlayerStats(IEnumerable stats)
{
foreach(stats中的Stat)
返回PlayerStats.FirstOrDefault(s=>stat.Id==s.PlayerStatistic.Id)??
新的PlayerStat(){PlayerStatistic=stat,XP=0};
屈服断裂;
}
这里的这个方法不需要
IQueryable
,而是需要
IEnumerable
通过
foreach
循环进行迭代,如果存在相应的
PlayerStats
对象,或者创建一个XP设置为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();
}
公共虚拟IList GetCompletePlayerStats(IEnumerable stats)
{
//根据ID构建现有统计数据的字典,以便于
//具有请求的统计信息的连接(有效地执行哈希连接)
var playerStatsById=PlayerStats.ToDictionary(ps=>ps.PlayerStatistic.Id);
//对于每个请求的属性,返回相应的玩家属性
//如果找不到,则为零状态,保持原始状态顺序
返回数据
.Select(s=>playerStatsById.ContainsKey(s.Id)?
playerStatsById[s.Id]:
新PlayerStat{PlayerStatistic=s,XP=0})
.ToList();
}
请注意,由于这实际上是一个外部联接操作(您将
stats
PlayerStats
联接,但您还需要非匹配项为零),因此您也可以使用LINQ的GroupJoin()操作来执行此操作,尽管我怀疑这可能不太可读

对你的设计来说,困扰我的是名字的模糊性,例如,你既有<代码> PraseSTAT< <代码>类,也有<代码> PraseSudio属性,它们意味着细微不同的事物;考虑不同地命名事物和事物可能看起来。