get_Keys()
действительно является допустимым (и рекомендуемым) способом доступа к свойству Keys
словаря без риска столкновения с пользовательским ключом.
Метод работает должным образом (также в других коллекциях, любой версии PowerShell и. Net Core):
Обратите внимание, что это работает только на словарях ([hashtable]
, [ordered]
, [SortedList]
et c.) - поскольку он унаследован от System.Collections.IDictionary
интерфейса .
Причина get_Keys()
не указана в публикации c документация такова, что она намеренно скрыта .
Чтобы понять почему, нам сначала нужно понять природу свойств in. NET
Свойства в. NET
В. NET, типы данных могут иметь различные типы членов . В приведенном ниже примере (C#) мы определяем класс с двумя членами: field и method :
class MyClass
{
int MyField;
int MyMethod(string n = "")
{
return int.Parse(n);
}
}
Интересно отметить здесь является то, что поле действует как переменная - мы можем ссылаться на него, чтобы получить значение любого целого числа, хранящегося в MyField
, и мы можем присвоить ему (новое) значение. С другой стороны, метод действует как функция - мы можем вызвать его, в том числе передать ему значения параметров, и он может вернуть значение.
Но. NET имеет третий тип типа элемента, который действует как бит гибридного между полем и методом, и выглядит примерно так (в случае словаря):
class MyDictionary
{
string[] Keys
{
string[] _keys;
get
{
return _keys;
}
set
{
throw new InvalidOperationException("Don't mess with the keys!");
}
}
}
Это известно как свойство - с точки зрения пользователя свойство Keys
будет действовать как поле - мы можем ссылаться на него, чтобы разрешить его значение, и мы можем (пытаться) присвоить ему - но с точки зрения разработчика у нас гораздо больше контроля над его поведением, например, возможность (условно) генерировать исключение при присваивании.
Теперь, когда приведенный выше код скомпилирован, компилятору C# требуется хранить методы get
и set
где-нибудь , чтобы CLR знал, как выполнить их, когда кто-то пытается разрешить элемент Keys
во время выполнения.
Соглашение состоит в том, чтобы генерировать их как обычные методы класса, названные с добавлением get_
и set_
к соответствующему имени свойства. Далее компилятор помечает эти методы флагом SpecialName
attribute , позволяя редакторам и анализаторам скрывать их в пользовательских интерфейсах и автозаполнениях - именно поэтому имя метода не отображается автоматически в intellisense и т.п..
Обнаружение получателей / установщиков свойств
* В классах PowerShell члены всегда являются либо методами , либо свойствами , поэтому в следующем Я буду использовать это определение класса PowerShell для примеров:
class StackOverflowUser
{
[string]$Name
[int]$ID
StackOverflowUser([string]$name, [int]$id)
{
$this.Name = $name
$this.ID = $ID
}
}
$Mathias = [StackOverflowUser]::new("Mathias R. Jessen", 712649)
Использование Get-Member
Вы можете обнаружить автоматические получатели и установщики c, связанные со свойством, используя Get-Member -Force
:
PS C:\> $Mathias |Get-Member ?et_* -Force
TypeName: StackOverflowUser
Name MemberType Definition
---- ---------- ----------
get_ID Method int get_ID()
get_Name Method string get_Name()
set_ID Method void set_ID(int )
set_Name Method void set_Name(string )
Здесь мы видим методы получения и установки, связанные с $ID
и $Name
.
Использование отражения
Мы также можем найти их непосредственно из a [type]
object:
PS C:\> $IDPropertyInfo = [StackOverflowUser].GetProperty("ID")
PS C:\> $IDPropertyInfo.GetMethod
Name : get_ID
DeclaringType : StackOverflowUser
ReflectedType : StackOverflowUser
MemberType : Method
MetadataToken : 100663299
Module : RefEmit_InMemoryManifestModule
IsSecurityCritical : True
IsSecuritySafeCritical : False
IsSecurityTransparent : False
MethodHandle : System.RuntimeMethodHandle
Attributes : PrivateScope, Public, HideBySig, SpecialName
CallingConvention : Standard, HasThis
ReturnType : System.Int32
ReturnTypeCustomAttributes : Int32
ReturnParameter : Int32
IsCollectible : True
IsGenericMethod : False
IsGenericMethodDefinition : False
ContainsGenericParameters : False
MethodImplementationFlags : Managed
IsAbstract : False
IsConstructor : False
IsFinal : False
IsHideBySig : True
IsSpecialName : True
IsStatic : False
IsVirtual : False
IsAssembly : False
IsFamily : False
IsFamilyAndAssembly : False
IsFamilyOrAssembly : False
IsPrivate : False
IsPublic : True
IsConstructedGenericMethod : False
CustomAttributes : {}
Обратите внимание, что приведенный выше метод получения имеет атрибут SpecialName
, как обсуждалось выше
Примечание: вывод выше сделан из PowerShell 7 и будет быть немного другим в Windows PowerShell из-за изменений в API системы отражения / типа в. NET Core
Надеюсь, это объясняет :)