C#数组属性和类结构

时间:2012-03-06 21:15:08

标签: c# oop class-structure

我班级的当前结构有点像这样: PC.Processor.Architecture [0] =第一个处理器的架构(假设是一个多处理器系统)。

我理想地希望它更像是这样的: PC.Processor [0]。架构,因为它通过这种方式更加自我解释。

有没有一种相当有效的方法来实现我的目标?请记住,每个类中有超过9000个属性处理器,主板,内存等,并且WMI调用运行时不便宜。

以下是我班级的重要摘录

class PC
{
    public Processor Processor;
    public Motherboard Motherboard;

    // Constructor
    public PC()
    {
        Processor = new Processor();
        Motherboard = new Motherboard();
    }

    // Method to get all info sequentially
    public void GetAllInfo()
    {
        Processor.GetInfo();
        Motherboard.GetInfo();
    }
}

class Processor
{
    public string[] Architecture;
    public string[] Availability;
    public UInt16[] Cores;

    public void GetInfo()
    {
        // Get WMI Information from custom process
        // Returns as an array of ManagementObjects for each matched device (which is a bit like an array of dictionaries)
        ManagementObject[] WMIData = DataRetriever.GetWMIData("Win32_Processor");
        try
        {
            for (int i = 1; i < WMIData.Length; i++)
            {
                this.Architecture[i] = (string)WMIData[i]["Architecture"];
                this.Availability[i] = (string)WMIData[i]["Availability"];
                this.Cores[i] = (UInt16)WMIData[i]["NumberOfCores"];
            }
        }
        catch (NullReferenceException e)
        {
            // To be implemented
        }
    }
}

此外
每个类可能有多个WMI搜索查询。例如,HardDrive需要同时使用Win32_PhysicalMedia和ATAPI_SmartData(或者实际上是类。)

3 个答案:

答案 0 :(得分:2)

你可能应该懒洋洋地打电话,例如:

class PC
{
    public IEnumerable<Processor> Processors {get; private set;}

    // Constructor
    public PC()
    {
        Processors = new List<Processor>();
        for (var i = 0; i < GetProcessorCount(); i++)
            Processors.Add(new Processor(i));
    }
}

class Processor
{
    public int ProcessorIndex { get; private set; }

    private String _architecture;
    public string Architecture { 
        get { 
            // Return architecture if it's already been retrieved, 
            // otherwise retrieve it, store it, and return it.
            return _architecture ?? (_architecture == getArchitecture(ProcessorIndex));
        }
    }
    public Processor(int processorIndex) {
        ProcessorIndex = processorIndex;
    }
}

通过这种方式,您可以获得所需的语义,例如

Console.Out.WriteLine(myPCInstance.Processors[0].Architecture);

同时您只是在实际要求时检索该信息。

答案 1 :(得分:1)

为什么不让Processor类只拥有单个属性ArchitectureCores等,并在其构造函数中使用ManagementObject实例?然后,您可以从Processor的构造函数中的管理对象中提取所需数据,并在Processor对象中创建许多PC

class PC
{
    //I'd encapsulate these in a property rather than a public field
    public Processor[] Processors;
    public Motherboard Motherboard;

    // Constructor
    public PC()
    {

        Motherboard = new Motherboard();
    }

    // Method to get all info sequentially
    public void GetAllInfo()
    {
        ManagementObject[] WMIData = DataRetriever.GetWMIData("Win32_Processor");
        Processors = new Processor[WMIData.Length-1];
        for (int i = 1; i < WMIData.Length; i++)
            {
            Processors[i-1] = new Processor(WMIData[i-1]); //assuming 0 based                
            }

        Motherboard.GetInfo();
    }
}

class Processor
{
    public string Architecture;
    public string Availability;
    public UInt16 Cores;

    public Processor(ManagementObject WMIData)
    {
        this.Architecture = (string)WMIData["Architecture"];
        this.Availability = (string)WMIData["Availability"];
        this.Cores = (UInt16)WMIData["NumberOfCores"];
    }
}

如果您担心性能,那么您应该隐藏属性后面的公共字段,然后根据需要随意拨打电话。显然,这是在您需要时加载数据(可能涉及访问时的延迟)或预加载所有数据之间的权衡(这可能意味着开始时的延迟,但在您需要时会很快)。所需的结果取决于您是否总是需要所有数据以及如何使用它们。

您可以将WMIData对象存储在Processor类中,只需在访问属性时读取值即可。这取决于慢位的位置:

class Processor
{ 
    private ManagementObject WMIData;
    // obviously you might want to cache this value once it has been retrieved once
    public string Architecture{get{return (string)WMIData["Architecture"];}}
    public string Availability {get{return (string)WMIData["Availability"];}}
    public UInt16 Cores{get{return (UInt16)WMIData["NumberOfCores"]}}

    public Processor(ManagementObject WMIData)
    {
        this.WMIData = WMIData;
    }
}

修改

如果你需要超过1个WMI查询,那么要么将每个WMI调用的结果传递给对象,以便它可以从它们获取数据(听起来它会很慢)或者给它足够的数据,这样就可以了在需要时拨打电话:

class HardDrive
{
   private int index;
   private ManagmentObject physicalMediaInfo;
   private ManagementObject smartDataInfo;

   // choose one of these constructors.  this one lets you delay all the WMI calls till you need to do them 
   public HardDrive(int index)
   {
       this.index=index;
   }

   //this one means you have to make the calls in advance
   public HardDrive(ManagmentObject physicalMediaInfo,ManagementObject smartDataInfo)
   {
       this.physicalMediaInfo=physicalMediaInfo;
       this.smartDataInfo=smartDataInfo;
   }

   private ManagementObject PhysicalMediaInfo
   {
       get
       { 
          if(physicalMediaInfo==null)
          {
              ManagementObject[] WMIData = DataRetriever.GetWMIData("Win32_PhysicalMedia");
              physicalMediaInfo=WMIData[index];
          } 
          return physicalMediaInfo;         
       }
   }

   private ManagementObject SmartDataInfo
   {
       get
       { 
          if(smartDataInfo==null)
          {
              ManagementObject[] WMIData = DataRetriever.GetWMIData("ATAPI_SmartData");
              smartDataInfo=WMIData[index];
          } 
          return smartDataInfo;         
       }
   }

   //property for getting the details of the hard disk
   //uses the private property to ensure that the management object for the  is only loaded when its needed
   public int Sectors{get{return (int)PhysicalMediaInfo["Sectors"]};};

   //Same for the smart data.  
   public int SomeSmartData{get{return (int)SmartDataInfo["SomeSmartData"]};};

}

这种方法允许您只需将每个api调用作为属性从中进行,并确保只执行一次,无论使用多少属性。您可以组合构造函数并允许传入的管理对象为null,然后您可以提供用于查找的索引和未使用构造函数传递的ManagementObject实例,但是您可以自由地传入一些ManagementObjects如果它们可用或便宜,可以预先加载......

编辑2

至于处理刷新,假设刷新需要确保下次访问数据时请求APi的最新信息,你应该能够简单地执行此操作:

 public void Refresh()
 {
     this.physicalMediaInfo=null;
     this.smartDataInfo=null;
 }

这将意味着下次调用Sectors时,将从WMIData中重新查询“Sectors”值,因为现有的WMIObject将被替换。

答案 2 :(得分:0)

感谢所有回复的人。 我想出了一个适合我需要的合理优雅的解决方案。

PC类示例:

public class PC
{
    public List<Processor> Processor;

    // Constructor
    public PC()
    {
        this.Processor = new List<Processor>();
    }

    // Method to get all info sequentially
    public void GetAllInfo()
    {
        // These temporary stores fetch WMI data as ManagementObjects
        // Most cases will only need one WMI class.
        ManagementObject[] WMIDataTemp1;
        ManagementObject[] WMIDataTemp2;

        WMIDataTemp1 = DataRetriever.GetWMIData("Win32_Processor");
        foreach (ManagementObject Object in WMIDataTemp1)
        {
            this.Processor.Add(new Processor(Object));
        }
    }

    public void RefreshAll()
    {
        // Delete the lists and start again
        // Another option would be to foreach through the list elements and initialise each object again.
        this.Processor.Clear();
        GetAllInfo();
    }

    public void RefreshVolatileData()
    {
        // Extra function that will do some cool stuff later.
    }
}

处理器类示例:

public class Processor
{
    // Define properties
    public string Architecture = "N/A";
    public string Availability = "N/A";
    public UInt32 CacheL2 = 0;
    public UInt32 CacheL3 = 0;

    // Overloaded constructor method
    // The one with no arguments does nothing to initialise the class
    // The one with the ManagementObject argument will call GetInfo to arrange the held data into the properties above
    public Processor() { }
    public Processor(ManagementObject wmiProcessor)
    {
        this.GetInfo(wmiProcessor);
    }

    // The main information handler for the classes.
    // This splits out the data in the ManagementObject into the class's own properties
    public void GetInfo(ManagementObject wmiProcessor)
    {
        // If anything fails, the try loop will just end without making a fuss
        // Because of the default values, N/A will be displayed everywhere if something fails here.
        try
        {
            this.Architecture = (string)wmiProcessor["Architecture"];
            this.Availability = (string)wmiProcessor["Availability"];
            this.CacheL2 = (UInt32)wmiProcessor["L2CacheSize"];
            this.CacheL3 = (UInt32)wmiProcessor["L3CacheSize"];
        }
        catch (Exception e)
        {

        }
    }
}

用法示例:

public PC Computer = new PC();
Computer.GetAllInfo();
textbox1.Text = Computer.Processor[0].Architecture

如果设备需要查询多个WMI类,则可以在设备构造函数和GetInfo()方法中将每个附加类列为额外参数。