1

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

理想情况下,我希望它更像这样:PC.Processor[0].Architecture,因为这种方式更易于自我解释。

有没有一种相当有效的方法可以用我所拥有的来做到这一点?请记住,处理器、主板、内存等每个类中都有超过 9000 个属性,并且 WMI 调用运行起来并不占用 CPU。

这是我的课程的重要片段

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(或任何实际的类)。

4

3 回答 3

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);

同时,您仅在实际要求时才检索该信息。

于 2012-03-06T21:29:07.397 回答
1

为什么不让一个Processor类只有单个属性ArchitectureCores并在其构造函数中获取一个ManagementObject实例?然后,您可以从 的构造函数中的管理对象中提取所需的数据,并在您的对象中Processor创建许多Processors 。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 对象存储在处理器类中,并在访问属性时读取值。这取决于慢位的位置:

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 调用作为需要的属性来执行,并确保它只执行一次,而不管使用了多少属性。您可以组合构造函数并允许传入的管理对象为空,然后您可以提供用于查找的索引和未通过构造函数传入的 ManagementObject 实例,但让您可以自由传递一些 ManagementObjects如果它们可用或便宜,则可以预加载...

编辑 2

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

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

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

于 2012-03-06T21:26:27.747 回答
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() 方法中将每个附加类列为额外参数。

于 2012-03-07T19:06:57.773 回答