两个列表包含一个接口,而一个列表包含具有两个接口的结构

本文关键字:列表 接口 两个 结构 包含具 包含一 一个 | 更新日期: 2023-09-27 18:26:46

我有两个接口。ICacheHolder将由一个实现游戏对象逻辑的类和作为视觉表示的IVisualizer来实现。

public interface ICacheHolder
{
    void updateCacheWithCurrentState(int chachFrame);
    void resizeCache(int newSize);
    T getCacheFrame<T>(int cacheIndex, float interpolationToNext) where T : struct;
}
public interface IVisualizer
{
    void updateVisualization(ICacheHolder cacheHolder, int cacheIndex, float interpolation);
}

每个ICacheHolder都连接到一个IVisualizer对象,关系是1到1。我试图确定将它们存储在两个单独的列表中还是作为结构存储在一个列表中更好(性能/内存方面)。会有很大的不同吗?如果我使用结构版本,会发生装箱吗?我估计名单的大小将从100到1000。

版本1:

public class CacheFramework
{
private List<ICacheHolder> cacheHolders = new List<ICacheHolder>();
private List<IVisualizer> visualizers = new List<IVisualizer>();
...
}

版本2:

struct SimulationObject
{
    public ICacheHolder CacheHolder;
    public IVisualizer Visualizer;
}
public class CacheFramework
{
private List<SimulationObject> cacheHolder = new List<SimulationObject>();
...
}

像添加和删除这样的操作不会经常执行。只是在比赛开始的时候,可能会有很多追加电话。

版本1:

private bool AddSimulationObject(ICacheHolder cacheHolder, IVisualizer visualizer)
{
    if (!cacheHolders.Contains(cacheHolder) && !visualizers.Contains(visualizer))
    {
        cacheHolders.Add(cacheHolder);
        visualizers.Add(visualizer);
        return true;
    }
    return false;
}

版本2:

private bool AddSimulationObject(ICacheHolder cacheHolder, IVisualizer visualizer)
{
    int index = simulationObjects.FindIndex(
        delegate (SimulationObject simulationObject)
        {
            return simulationObject.CacheHolder == cacheHolder || simulationObject.Visualizer == visualizer;
        }
        );
    if (index >= 0 )
    {
        SimulationObject newObject;
        newObject.CacheHolder = cacheHolder;
        newObject.Visualizer = visualizer;
        return true;
    }
    return false;
}

该列表将至少被访问每个帧通过其索引。

其他信息:使用ICacheHolder的每个类都将包含一个List<struct>,其中包含位置、旋转或健康等数据。每个列表元素都将是一个时间快照。目标是在时间中来回移动。

编辑1:

修复了AddSimulationObject版本2中的错误。

如前所述,AddSimulationObject版本2可能是:

private bool AddSimulationObject(ICacheHolder cacheHolder, IVisualizer visualizer)
{
    SimulationObject newObject = new SimulationObject { CacheHolder = cacheHolder, Visualizer = visualizer };
    if (simulationObjects.Contains(newObject))
    {
        simulationObjects.Add(newObject);
        return true;
    }
    return false;
}

但在这种情况下,我需要确保cacheHolder和可视化工具不会出现在任何其他组合中。

编辑2:

我使用的是Unity3D,它主要支持NET。3.5

正如所指出的,使用查找速度比List更快的.NET集合可能更好。或者,如果列表可以排序,请使用list.BinarySearch.

编辑3:

我将使用结构版本。我不确定会有多少查找。如果出现问题,我可能会换成另一个.NET集合。

两个列表包含一个接口,而一个列表包含具有两个接口的结构

Eric Lippert的评论非常正确。在这种情况下,甚至不需要尝试比较性能差异,因为集合非常小,所以不需要担心cpu时间。

记忆。。。列表结构使用连续的内存块,只有当它们真的很大时才会成为内存问题。(我指的是数百万。)

只有其他建议:如果每个游戏周期你都要在这些列表中进行搜索,你可以简单地选择另一个针对查找进行优化的结构。Dictionary在检索项方面要有效得多,因为find从索引中进行查找,而列表将执行项的遍历。

我建议您使用struct方法,原因有两个:

  • 在.NET中,结构的泛型类型参数被特殊处理,不会出现装箱
  • 这种方法将确保通过结构将匹配的元素组合在一起。对我来说,这感觉更容易推理

因此,当谈到是使用结构列表还是列表结构时,我当然更喜欢使用结构列表,即使它会导致性能下降。在您的情况下,我希望结构版本列表能更好地执行,但我不能保证。您可以随时运行评测。但有一点是肯定的:性能差异远小于AddSimulationObject中线性搜索的成本。

您谈论的是引用列表,您的任何一个解决方案都可以。但是,如果您的两个接口是成对的,您可以使用List<Tuple<ICacheHolder, IVisualizer>>