Правильно ли использовать метод get_Keys () для коллекций? - PullRequest
2 голосов
/ 23 марта 2020

Относящийся к этому вопросу: Могу ли я добавить ключ с именем 'keys' в хеш-таблицу без переопределения элемента 'keys' , на самом деле я часто использую метод get_Keys() как рекомендуемое свойство PSBase просто переместит проблему.
Другими словами, этот метод особенно удобен для неизвестного списка ключей каталога в случае решения, подобного: Powershell Merge 2 списка Производительность .

Метод работает должным образом (также в других коллекциях, любой версии PowerShell и. Net Core):

$Hash = @{Keys = 'MyKeys'; PSBase = 'MyPSBase'}
$Hash.get_Keys()
PSBase
Keys

Метод get_Keys(), по-видимому, является производным от:

$Hash.get_Keys

OverloadDefinitions
-------------------
System.Collections.ICollection get_Keys()
System.Collections.ICollection IDictionary.get_Keys()

Дело в том, что я не могу найти, где нашел ссылку на этот метод get_Keys(), и вряд ли есть документация по этому методу.
Безопасно ли использовать этот метод?

1 Ответ

3 голосов
/ 23 марта 2020

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

Надеюсь, это объясняет :)

...