Почему GetType() возвращает Object[] как тип в массиве, но ошибка вызова неправильного метода говорит, что это тип, который находится в 0-м элементе массива?

Итак, я создаю массив, вызываю GetType() и (разумно) получаю ответ Object[]. Однако, если я даю ему плохой метод, я получаю тип 0-го элемента в сообщении об ошибке.

Просто пытаюсь понять Powershell больше - я предполагаю, что это связано с тем, что Powershell разворачивает массив в случае, если он не находит метод в массиве, а затем также терпит неудачу в 0-м массиве, который выдает полную ошибку?

PS C:\Users\x> $i = @(1)
PS C:\Users\x> $i.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

PS C:\Users\x> $i.HerpDerp()
InvalidOperation: Method invocation failed because [System.Int32] does not contain a method named 'HerpDerp'.
PS C:\Users\x> $a = @("hi")
PS C:\Users\x> $a.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

PS C:\Users\x> $a.HerpDerp()
InvalidOperation: Method invocation failed because [System.String] does not contain a method named 'HerpDerp'.
PS C:\Users\x> $m = @("hi",1)
PS C:\Users\x> $m.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

PS C:\Users\x> $m.HerpDerp()
InvalidOperation: Method invocation failed because [System.String] does not contain a method named 'HerpDerp'.

Это связано с тем, что оператор вызова члена попытается вызвать содержащиеся элементы, если запрошенный элемент не найден в самом массиве — эта функция/поведение известно как перечисление доступа к члену

Mathias R. Jessen 12.05.2023 17:30

В значительной степени то, что вы указали в вопросе, верно, это также объясняется в документе «Перечисление членского доступа»: «Во время перечисления членского доступа для метода оператор пытается вызвать метод для каждого элемента в коллекции. Если какой-либо элемент в в коллекции нет указанного метода, оператор возвращает исключение MethodNotFound."

Santiago Squarzon 12.05.2023 17:31

Спасибо! У меня было ощущение, что это было задумано, но я не мог понять, как понять, как называется механизм.

Dustin Sollick 12.05.2023 18:09
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
1
3
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Соответствующая информация находится в комментариях, но я думаю, что ваш вопрос заслуживает ответа:

То, что вы видите, — это эффекты перечисления доступа к элементам, удобной функции PowerShell, где доступ к члену (свойству или методу) в массиве (спископодобной коллекции) неявно обращается к этому члену в его элементах, один за другим. , и возвращает результаты в виде массива, за исключением случаев, когда есть только один результат, который возвращается как есть;[1] например:

# Even though .Year is applied to the *array*, PowerShell returns 
# the .Year property values from the two [datetime] instances that
# are the *elements* of that array; e.g., in 2023: 
#   @( 2023, 2022 )
@( (Get-Date), (Get-Date).AddYears(-1) ).Year

Это работает только в том случае, если указанный элемент не существует в самом массиве, поскольку собственный элемент массива имеет приоритет; например.:

# Returns 3, the *array's* .Length property value (count of elements), 
# not the length of the strings stored in the array's elements.
@( 'foo', 'bar', 'baz' ).Length

Это также объясняет, почему $i.GetType() возвращает тип массива.


Когда применяется перечисление доступа к членам, поведение (по умолчанию) различается в зависимости от того, обращаетесь ли вы к свойству или методу:

  • Доступ к собственности:

    • Любой элемент массива, не имеющий указанного свойства, просто не участвует в выводе; если ни один элемент массива не имеет такого свойства, общий результат равен $null

      # Outputs only 2023 (for instance), because [int] 42 has no .Year property.
      @( (Get-Date), 42 ).Year
      
      • Примечание. Если свойство существует, но содержит $null, оно включается в результаты.
        Однако из-за ошибки, присутствующей как минимум до PowerShell 7.3.4, экземпляры [pscustomobject] также вносят свой вклад $null, если свойство не существует — см. GitHub issue #13752
  • Доступ к методу:

    • Если какой-либо элемент массива не имеет метода с указанным именем — или если вызов метода приводит к исключению — возникает ошибка завершения оператора, что означает отсутствие успешного вывода и сообщается только об одной ошибке, а именно для первый элемент, у которого не было метода/вызвал исключение (это объясняет результаты ваших .HerpDerp() вызовов):

      # !! Statement fails as a whole, because [int] (System.Int32)
      # !! doesn't have a .ToShortDateString() method.
      @( (Get-Date), 42 ).ToShortDateString()
      
      • Обратите внимание, что хотя вы можете обработать/замолчать такую ​​ошибку с помощью оператора try/catch, вы все равно не получите частичных результатов от тех элементов массива, которые имеют метод (и не вызвали исключения).

Обратите внимание, что вышеизложенное подразумевает, что это не обязательно первый элемент, который вызывает ошибку завершения оператора, и если это не так, результаты вызовов более ранних элементов фактически отбрасываются. Это несколько проблематично, учитывая, что вызовы методов могут иметь побочные эффекты (и, возможно, не иметь вывода), и в этом случае вам может потребоваться определить постфактум, для каких элементов были успешно выполнены вызовы методов.


[1] In doing so, member-access enumeration mimics the behavior of PowerShell's pipeline, which may be surprising. See GitHub issue #6802 for a discussion.

Другие вопросы по теме