我班级的当前结构有点像这样: 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(或者实际上是类。)
答案 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
类只拥有单个属性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;
}
}
修改强>
如果你需要超过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()方法中将每个附加类列为额外参数。