如何覆盖 PowerShell 中 Collection 对象的 "member enumeration" 行为
How to override the "member enumeration" behavior of Collection objects in PowerShell
想象一下,我创建了一个 C# class 扩展 Collection<T>
来为特定用例添加额外的功能。
public class MyCollection<T> : Collection<T> {}
现在,如果我将这个 class 导入到我的 PowerShell 脚本中,并实例化这样一个对象,从所述对象调用 T
对象的成员方法将执行一种“魔术” - 为集合中的每一项依次调用成员方法的幕后花絮。
请注意,在此示例中,我使用自己的 MyCollection[String]
而不是 Collection[String]
没有任何区别。
Add-Type -Path ".\MyCollection.cs"
$test = New-Object -TypeName MyCollection[String]
$test.Add("one")
$test.Add("two")
$test.Add("three")
$test.Length
# 3
# 3
# 5
此行为或多或少被称为“成员枚举”。到这里来解释我在说什么:https://devblogs.microsoft.com/powershell/new-v3-language-features/
因为它实际上不是 运行 ForEach-Object cmdlet(参考上面 link),我希望找到 实际上 是什么关于以及如何,如果可能的话,我可以覆盖该行为而无需进行复杂的解决方法(例如在 MyCollection class 中为对象 class 中的每个方法创建一个包装方法)。
例如:
public class MyCollection<T> : Collection<T> {
public new void ForEach-Object(this Action action) {
DoSomethingAsync(this, action);
}
}
我故意使用上面的无效语法来帮助说明问题。我真的不知道这是否可以做到。
或者,如果有另一种方法可以实现同样的事情 而无需 执行我之前提到的解决方法,我也有兴趣听听这些想法。
最终,所有这些集合类型都将实现 IEnumerable
接口,该接口使用 GetEnumerator 方法迭代对象集合,无论是在 .NET foreach
在您的 PowerShell Foreach-Object
cmdlet 中循环。
一些具体的 Collection 实现将允许您提供自己的 GetEnumerator
实现,而其他的则不允许。我想不出有什么能让它脱离我的脑海,但我知道 Collection<T>
不会。如果您需要覆盖此功能,您可以尝试使用 new
关键字隐藏 GetEnumerator
,正如您在上面演示的那样,它应该可以正常工作。另一种选择是编写自己的集合 class 来实现 IEnumerable,但这听起来很痛苦。
您可以 not 阻止 PowerShell 的 member-access enumeration(同时不使您的集合不可枚举),因为它是.
成员访问运算符内置的行为。
但是,您可以在访问成员时绕过它需要额外的努力,即通过 intrinsic .psbase
property:[1]
((Get-Item /), (Get-Item /)).Name # Member(-access) enumeration
((Get-Item /), (Get-Item /)).psbase.Name # NO enumeration, only the array's
# own members.
但是,如果您引用集合对象本身存在的 属性,则集合级别 属性 是 使用,覆盖成员访问枚举。
也就是说,$test.Count
- 假设 .Count
是你的集合类型的一个(实例)成员 - return 只是 3
,元素的数量集合。
GitHub suggestion #7445 要求为成员访问枚举提供不同的语法(运算符),但只要 PowerShell 继续致力于向后兼容(可能永远如此),.
的行为就会不变。
[1] 请注意,.psbase
属性 仅 调解 仅限于类型原生成员的成员访问。 .psbase
的值本身是一个 [pscustomobject]
实例,其 ETS(扩展类型系统)名称为 System.Management.Automation.PSMemberSet
。
想象一下,我创建了一个 C# class 扩展 Collection<T>
来为特定用例添加额外的功能。
public class MyCollection<T> : Collection<T> {}
现在,如果我将这个 class 导入到我的 PowerShell 脚本中,并实例化这样一个对象,从所述对象调用 T
对象的成员方法将执行一种“魔术” - 为集合中的每一项依次调用成员方法的幕后花絮。
请注意,在此示例中,我使用自己的 MyCollection[String]
而不是 Collection[String]
没有任何区别。
Add-Type -Path ".\MyCollection.cs"
$test = New-Object -TypeName MyCollection[String]
$test.Add("one")
$test.Add("two")
$test.Add("three")
$test.Length
# 3
# 3
# 5
此行为或多或少被称为“成员枚举”。到这里来解释我在说什么:https://devblogs.microsoft.com/powershell/new-v3-language-features/
因为它实际上不是 运行 ForEach-Object cmdlet(参考上面 link),我希望找到 实际上 是什么关于以及如何,如果可能的话,我可以覆盖该行为而无需进行复杂的解决方法(例如在 MyCollection class 中为对象 class 中的每个方法创建一个包装方法)。
例如:
public class MyCollection<T> : Collection<T> {
public new void ForEach-Object(this Action action) {
DoSomethingAsync(this, action);
}
}
我故意使用上面的无效语法来帮助说明问题。我真的不知道这是否可以做到。
或者,如果有另一种方法可以实现同样的事情 而无需 执行我之前提到的解决方法,我也有兴趣听听这些想法。
最终,所有这些集合类型都将实现 IEnumerable
接口,该接口使用 GetEnumerator 方法迭代对象集合,无论是在 .NET foreach
在您的 PowerShell Foreach-Object
cmdlet 中循环。
一些具体的 Collection 实现将允许您提供自己的 GetEnumerator
实现,而其他的则不允许。我想不出有什么能让它脱离我的脑海,但我知道 Collection<T>
不会。如果您需要覆盖此功能,您可以尝试使用 new
关键字隐藏 GetEnumerator
,正如您在上面演示的那样,它应该可以正常工作。另一种选择是编写自己的集合 class 来实现 IEnumerable,但这听起来很痛苦。
您可以 not 阻止 PowerShell 的 member-access enumeration(同时不使您的集合不可枚举),因为它是.
成员访问运算符内置的行为。
但是,您可以在访问成员时绕过它需要额外的努力,即通过 intrinsic
.psbase
property:[1]((Get-Item /), (Get-Item /)).Name # Member(-access) enumeration ((Get-Item /), (Get-Item /)).psbase.Name # NO enumeration, only the array's # own members.
但是,如果您引用集合对象本身存在的 属性,则集合级别 属性 是 使用,覆盖成员访问枚举。
也就是说,$test.Count
- 假设 .Count
是你的集合类型的一个(实例)成员 - return 只是 3
,元素的数量集合。
GitHub suggestion #7445 要求为成员访问枚举提供不同的语法(运算符),但只要 PowerShell 继续致力于向后兼容(可能永远如此),.
的行为就会不变。
[1] 请注意,.psbase
属性 仅 调解 仅限于类型原生成员的成员访问。 .psbase
的值本身是一个 [pscustomobject]
实例,其 ETS(扩展类型系统)名称为 System.Management.Automation.PSMemberSet
。