访问类的重对象成员的正确方法

时间:2015-03-09 17:36:46

标签: c# .net performance profiler

我有一个这样的课程:

class BuildingFloor
{
    // The list of building rooms;
    // Room is "heavy" object with many-many fields
    List< Room > m_rooms;

    // The list of all apertures on the floor
    List< Aperture > m_apertures;
    ...
    List< Room > Rooms
    {
        get { return m_rooms; }
    }

    List< Aperture > Doors
    {
        get{ return GetAperturesOfType( 2 ); }
    }
    public List< Aperture > Exits
    {
        get{ return GetAperturesOfType( 3 ); }
    }
    ...
    List< Aperture > GetAperturesOfType( int type )
    {
        var apertures = new List<ApertureWrapper>();
        foreach ( var aper in m_apertures )
        {
            if ( ( aper.Type == type ) )
            {
                apertures.Add( aper );
            }
        }
        return apertures;
    }
}

我的问题是:
1)当客户端代码访问m_rooms属性时,将复制Rooms;
2)在List<>属性调用上构建Doors个对象的次数。

那么,我可以在此代码中更改哪些内容以使其更快? 我需要在代码中大量使用这些属性 foreach( var door in m_floor.Doors) { ... }
注意:Profiler说Exits属性花费了大量时间。证明:Visual Studio Profiler screenshot

1 个答案:

答案 0 :(得分:4)

  

当客户端代码访问Rooms属性

时,是否会复制m_rooms

是。但m_rooms的值只是一个引用 - 它本身不是List<Room>对象。您可能想阅读我关于reference types and value types的文章。

  

在Doors属性调用上构造List<>个对象的次数。

  1. 它正在调用GetAperturesOfType一次,构建一个新的List<ApertureWrapper>
  2. 您的财产将更简单地实施为:

    return m_apertures.Where(x => x.Type == 2).ToList();
    

    (听起来你可能也需要一个ApertureType枚举...)

    另请注意,如果只是需要遍历大门,您可以使用:

    return m_apertures.Where(x => x.Type == 2);
    

    并且完全避免创建List<>。在其他方面,这会有不同的语义,请注意......

      

    Profiler说Doors的财产花了很多时间。

    嗯,你需要看看你实际获得了多少个光圈,有多少个光门,以及你调用Doors属性的频率。我们无法从你向我们展示的内容中真正分辨出什么是重要的。绩效工作通常是情境性的。

    编辑:现在我们已经看到了调用代码,如果使用局部变量会更好:

    var exits = m_building.CurrentFloor.Exits;
    for (int i = 0; i < exits.Count; i++)
    {
        // Use exits[i] within here
        // Set exitId to i + 1 if you find the exit.
        // (Or ideally, change everything to be 0-based...)
    }
    

    否则,您将为循环的每次迭代创建一个新列表。