Свойства массива C # и структура классов - PullRequest
1 голос
/ 07 марта 2012

Текущая структура моих классов выглядит примерно так: PC.Processor.Architecture [0] = Архитектура первого процессора (предполагается, что многопроцессорная система).

Как я хочу в идеалеэто больше похоже на: PC.Processor [0] .Architecture, потому что он немного более понятен.

Есть ли достаточно эффективный способ сделать это с тем, что у меня есть?Имейте в виду, что более 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 ]

2 голосов
/ 07 марта 2012

Вы, вероятно, должны делать эти вызовы лениво, например ::1001

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 голос
/ 07 марта 2012

почему бы не сделать класс Processor просто имеющим отдельные свойства Architecture, Cores и т. Д. И взять экземпляр 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;
    }
}

EDIT

если вам нужно более одного запроса 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;
 }

Это будет означать, что в следующий раз, когда Секторы будут называться, значение "Секторы" будет запрашиваться из WMIData, поскольку существующий объект WMIO будет заменен.

0 голосов
/ 07 марта 2012

Спасибо всем, кто откликнулся.Я нашел довольно элегантное решение, которое соответствует моим потребностям.

Пример класса ПК:

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 ().

...