就标题和 TL;DR 的要求而言,无法通过方法查询方法,SELECT
但您可以使用该ManagementClass.Methods
属性来检查该管理类提供的方法。例如,这段代码...
using (ManagementClass processClass = new ManagementClass("Win32_Process"))
foreach (MethodData method in processClass.Methods)
{
bool isStatic = method.Qualifiers
.Cast<QualifierData>()
.Any(qualifier => string.Equals(qualifier.Name, "Static", StringComparison.OrdinalIgnoreCase));
Console.WriteLine($"{method.Origin}.{method.Name}() [{(isStatic ? "static" : "instance")}]");
if (method.InParameters != null && method.InParameters.Properties.Count > 0)
{
Console.WriteLine("\tInput parameters:");
foreach (PropertyData parameterProperty in method.InParameters.Properties)
Console.WriteLine($"\t\t{parameterProperty.Type} {parameterProperty.Name}");
}
if (method.OutParameters != null && method.OutParameters.Properties.Count > 0)
{
Console.WriteLine("\tOutput parameters:");
foreach (PropertyData parameterProperty in method.OutParameters.Properties)
Console.WriteLine($"\t\t{parameterProperty.Type} {parameterProperty.Name}");
}
}
...产生这个输出...
Win32_Process.Create() [static]
Input parameters:
String CommandLine
String CurrentDirectory
Object ProcessStartupInformation
Output parameters:
UInt32 ProcessId
UInt32 ReturnValue
Win32_Process.Terminate() [instance]
Input parameters:
UInt32 Reason
Output parameters:
UInt32 ReturnValue
Win32_Process.GetOwner() [instance]
Output parameters:
String Domain
UInt32 ReturnValue
String User
...
除非“获取方法”的含义与我认为的不同(与调用方法不同),否则问题的其余部分似乎完全是在处理其他事情,这是Key
在调用方法之前填充属性的必要性。我相信这在您的另一个问题中得到了解决,为什么 WMI 通过搜索而不是直接工作?
如果您真正要问的是“如何确定调用方法所需选择的最少属性集?”,那么您也可以使用ManagementClass
. 该最小属性集都是带有Key
qualifier的属性,因此您可以使用该Properties
属性来查找其Qualifiers
属性包含带有Name
of的限定符的任何属性"Key"
。
考虑Win32_Product
class,它代表由 Windows Installer 安装的产品,并且(在我的 Windows 10 系统上确定,与文档不同)具有这些Key
属性......
IdentifyingNumber
Name
Version
假设您要检索这些属性以显示...
PackageName
Vendor
Version
...然后调用具有of的产品的Uninstall()
方法。以下代码显示了尝试此任务的三种不同方法...Name
"Microsoft .NET Framework 4.8 SDK"
- 选择所有属性并调用该方法。
- 仅选择要显示的属性并调用该方法。
- 选择要显示的属性以及
Key
属性并调用该方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
namespace SO49798851
{
static class Program
{
static void Main()
{
// Win32_Product is slow to query, so be patient!
const string className = "Win32_Product";
const string condition = "Name = 'Microsoft .NET Framework 4.8 SDK'";
string[] allProperties = new string[] { "*" };
string[] displayProperties = new string[] { "PackageName", "Vendor", "Version" };
string[] keyProperties = GetKeyPropertyNames(className);
string[] displayPlusKeyProperties = displayProperties.Union(keyProperties).ToArray();
// When run as a non-administrator, the Uninstall() method
// still returns 0 despite not (appearing to) do anything
const string methodName = "Uninstall";
object[] methodArguments = Array.Empty<object>();
Console.WriteLine($"Key properties for class {className}: {string.Join(", ", keyProperties)}");
Console.WriteLine();
FindAndInvoke(className, condition, allProperties, methodName, methodArguments);
FindAndInvoke(className, condition, displayProperties, methodName, methodArguments);
FindAndInvoke(className, condition, displayPlusKeyProperties, methodName, methodArguments);
}
static string[] GetKeyPropertyNames(string className)
{
using (ManagementClass managementClass = new ManagementClass(className))
{
return managementClass.Properties
.Cast<PropertyData>()
.Where(
property => property.Qualifiers
.Cast<QualifierData>()
.Any(qualifier => string.Equals(qualifier.Name, "Key", StringComparison.OrdinalIgnoreCase))
)
.Select(property => property.Name)
.ToArray();
}
}
static void FindAndInvoke(
string className,
string condition,
string[] selectedProperties,
string methodName,
object[] methodArguments
)
{
if (selectedProperties == null)
selectedProperties = Array.Empty<string>();
ObjectQuery query = new SelectQuery(className, condition, selectedProperties);
bool allPropertiesSelected = selectedProperties.Length < 1
|| selectedProperties.Any(propertyName => propertyName == "*");
Console.WriteLine(query.QueryString);
Console.WriteLine(new string('=', query.QueryString.Length));
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
using (ManagementObjectCollection searchResultCollection = searcher.Get())
{
// ManagementObjectCollection doesn't support indexing; this is the
// least-ugly, least-verbose way to enumerate it with an index variable
ManagementObject[] searchResultArray = searchResultCollection.Cast<ManagementObject>().ToArray();
for (int i = 0; i < searchResultArray.Length; i++)
using (ManagementObject searchResult = searchResultArray[i])
{
Console.WriteLine($"{className}[{i}].Path.RelativePath: {searchResult.Path.RelativePath}");
Console.WriteLine($"{className}[{i}].Properties.Count: {searchResult.Properties.Count}");
foreach (PropertyData property in searchResult.Properties)
if (allPropertiesSelected
|| selectedProperties.Contains(property.Name, StringComparer.OrdinalIgnoreCase)
)
{
object displayValue = property.Value ?? "<null>";
Console.WriteLine($"{className}[{i}].Properties[\"{property.Name}\"]: {displayValue}");
}
try
{
object methodResult = searchResult.InvokeMethod(methodName, methodArguments);
Console.WriteLine($"{className}[{i}].{methodName}() completed with result {methodResult}.");
}
catch (Exception ex)
{
Console.WriteLine($"{className}[{i}].{methodName}() failed with {ex}.");
}
Console.WriteLine();
}
}
}
}
}
...并产生此输出...
Key properties for class Win32_Product: IdentifyingNumber, Name, Version
select * from Win32_Product where Name = 'Microsoft .NET Framework 4.8 SDK'
===========================================================================
Win32_Product[0].Path.RelativePath: Win32_Product.IdentifyingNumber="{949C0535-171C-480F-9CF4-D25C9E60FE88}",Name="Microsoft .NET Framework 4.8 SDK",Version="4.8.03928"
Win32_Product[0].Properties.Count: 27
Win32_Product[0].Properties["AssignmentType"]: 1
Win32_Product[0].Properties["Caption"]: Microsoft .NET Framework 4.8 SDK
Win32_Product[0].Properties["Description"]: Microsoft .NET Framework 4.8 SDK
Win32_Product[0].Properties["HelpLink"]: <null>
Win32_Product[0].Properties["HelpTelephone"]: <null>
Win32_Product[0].Properties["IdentifyingNumber"]: {949C0535-171C-480F-9CF4-D25C9E60FE88}
Win32_Product[0].Properties["InstallDate"]: 20191001
Win32_Product[0].Properties["InstallDate2"]: <null>
Win32_Product[0].Properties["InstallLocation"]: <null>
Win32_Product[0].Properties["InstallSource"]: C:\ProgramData\Microsoft\VisualStudio\Packages\Microsoft.Net.4.8.SDK,version=4.8.3928.1\
Win32_Product[0].Properties["InstallState"]: 5
Win32_Product[0].Properties["Language"]: 1033
Win32_Product[0].Properties["LocalPackage"]: C:\WINDOWS\Installer\34d24bd7.msi
Win32_Product[0].Properties["Name"]: Microsoft .NET Framework 4.8 SDK
Win32_Product[0].Properties["PackageCache"]: C:\WINDOWS\Installer\34d24bd7.msi
Win32_Product[0].Properties["PackageCode"]: {CC6C9CC4-DDCD-4C14-81E1-4007EE49D7C0}
Win32_Product[0].Properties["PackageName"]: sdk_tools48.msi
Win32_Product[0].Properties["ProductID"]: <null>
Win32_Product[0].Properties["RegCompany"]: <null>
Win32_Product[0].Properties["RegOwner"]: <null>
Win32_Product[0].Properties["SKUNumber"]: <null>
Win32_Product[0].Properties["Transforms"]: <null>
Win32_Product[0].Properties["URLInfoAbout"]: <null>
Win32_Product[0].Properties["URLUpdateInfo"]: <null>
Win32_Product[0].Properties["Vendor"]: Microsoft Corporation
Win32_Product[0].Properties["Version"]: 4.8.03928
Win32_Product[0].Properties["WordCount"]: 0
Win32_Product[0].Uninstall() completed with result 0.
select PackageName,Vendor,Version from Win32_Product where Name = 'Microsoft .NET Framework 4.8 SDK'
====================================================================================================
Win32_Product[0].Path.RelativePath:
Win32_Product[0].Properties.Count: 3
Win32_Product[0].Properties["PackageName"]: sdk_tools48.msi
Win32_Product[0].Properties["Vendor"]: Microsoft Corporation
Win32_Product[0].Properties["Version"]: 4.8.03928
Win32_Product[0].Uninstall() failed with System.InvalidOperationException: Operation is not valid due to the current state of the object.
at System.Management.ManagementObject.InvokeMethod(String methodName, Object[] args)
at SO49798851.Program.FindAndInvoke(String className, String condition, String[] selectedProperties, String methodName, Object[] methodArguments) in ...\Program.cs:line 90.
select PackageName,Vendor,Version,IdentifyingNumber,Name from Win32_Product where Name = 'Microsoft .NET Framework 4.8 SDK'
===========================================================================================================================
Win32_Product[0].Path.RelativePath: Win32_Product.IdentifyingNumber="{949C0535-171C-480F-9CF4-D25C9E60FE88}",Name="Microsoft .NET Framework 4.8 SDK",Version="4.8.03928"
Win32_Product[0].Properties.Count: 5
Win32_Product[0].Properties["IdentifyingNumber"]: {949C0535-171C-480F-9CF4-D25C9E60FE88}
Win32_Product[0].Properties["Name"]: Microsoft .NET Framework 4.8 SDK
Win32_Product[0].Properties["PackageName"]: sdk_tools48.msi
Win32_Product[0].Properties["Vendor"]: Microsoft Corporation
Win32_Product[0].Properties["Version"]: 4.8.03928
Win32_Product[0].Uninstall() completed with result 0.
以下是这三种尝试的收获……
- 当然,选择所有属性会导致方法调用成功,但我们最终会得到比我们想要的更多的属性。
- 准确选择我们想要的属性 - 但不是所有
Key
属性 - 会导致方法调用失败。
- 准确选择我们想要的属性加上这些
Key
属性会导致成功的方法调用没有多余的属性。
- 如果我们有一个我们想要的属性集合(即
displayProperties
)和一个Key
属性集合(即keyProperties
),Union()
LINQ 方法可以很容易地将它们组合起来以获得最少的属性来选择。