LA.Net
Reflexões sobre C#, .Net e programação em geral

Após um longo interregno, os posts sobre Monad estão de volta

Apesar de ter prometido falar sobre a formatação dos dados, hoje vou falar um pouco acerca da extensão dos tipos usados pelo Monad. Como vimos nos posts anteriores, podemos obter os ficheiros contidos numa pasta através do seguinte comando:

MSH c:\>gci

 Directory: Microsoft.Management.Automation.Core\FileSystem::C:\Documents an
    d Settings\labreu


Mode                LastWriteTime     Length Name                             
----                -------------     ------ ----                             
-a---        23-03-2006      9:18          0 a.txt                            
-a---        09-03-2006     12:50          0 Sti_Trace.log                    
d----        14-03-2006      9:28            .borland                         
d----        14-03-2006      9:28            .dtc  

A grande vantagem do Monad reside no facto desta shell trabalhar apenas com objectos. Se analisarmos o tipo retornado pelo comando anterior, facilmente nos apercebemos que o cmdlet retorna um array de objectos (Object[]):

MSH c:\>$(gci).GetType()


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

Se quisermos analisar o número de elementos retornados, podemos executar o seguinte comando:

MSH c:\>$(gci).Length

14

Contudo, também podemos executar o seguinte comando e obter o mesmo resultado:

MSH c:\>$(gci).Count

Uma consulta rápida à documentaçao revela que a propriedade Count não faz parte da classe System.Array (usada como base de todos os arrays em .NET). Mas então o que se está a passar?

O Monad permite a fácil extensão de tipos e a criação de de aliases às propriedades de tipos existentes. Por predefinição, o ficheiro types.mshxml contém as extensões standard introduzidas pela shell. O comando anterior funcionou correctamente devido à seguinte entrada existente no ficheiro types.mshxml:

<Type>
        <Name>System.Array</Name>
        <Members>
            <AliasProperty>
                <Name>Count</Name>
                <ReferencedMemberName>Length</ReferencedMemberName>
            </AliasProperty>
        </Members>
    </Type>

Como é possível verificar, a propriedade Lenght possui um alias designado de Count. Para além destas entradas simples, podemos ainda encontrar outro tipo de entradas (note-se que cada tipo é identificado unicamente por elementos do tipo <Type>). Se voltarmos a analisar o exemplo responsável pela apresentação da listagem de ficheiros/directórios apresentados no início do post, verificamos que cada elemento retornado possui uma propriedade Mode (como vimos anteriormente, os elementos retornados são do tipo DirectoryInfo ou FileInfo – esta informação pode ser facilmente verificada através da execução do comando gci | gm). Tal como acontecia com a propriedade Count, também a propriedade Mode representa uma extensão ao modelo disponibilizado pelas classes DirectoryInfo e FileInfo. Vamos analisar a entrada  associada ao tipo FileInfo:

<Type>
        <Name>System.IO.FileInfo</Name>
        <Members>
            <ScriptProperty>
                <Name>Mode</Name>
                <GetScriptBlock>
                    $catr = "";
                    if ( $this.Attributes -band 16 ) { $catr += "d" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 32 ) { $catr += "a" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 1 )  { $catr += "r" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 2 )  { $catr += "h" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 4 )  { $catr += "s" } else { $catr += "-" } ;
                    $catr
                </GetScriptBlock>
            </ScriptProperty>
            <MemberSet>
                <Name>MshStandardMembers</Name>
                <Members>
                    <NoteProperty>
                        <Name>SerializationDepth</Name>
                        <Value>1</Value>
                    </NoteProperty>
                    <PropertySet>
                        <Name>DefaultDisplayPropertySet</Name>
                        <ReferencedProperties>
                            <Name>LastWriteTime</Name>
                            <Name>Length</Name>
                            <Name>Name</Name>
                        </ReferencedProperties>
                    </PropertySet>
                </Members>
            </MemberSet>
        </Members>
    </Type>

Como é possível verificar, a propriedade Mode é definida através de um bloco de script (introduzido através do termo GetScriptBlock). Para além deste novo elemento, o excerto anterior ilustra ainda outros elementos que podem ser introduzidos num ficheiro deste género. A utilização de um elemento MemberSet com o nome MshStandardMembers permite a definição das propriedades que são apresentados quando necessitamos de informação acerca de um objecto. No interior de um elemento MemberSet, podemos ter vários tipos de elementos. A definição de um PropertySet com o nome DefaultDisplayPropertySet é especial já que permite um conjunto de propriedades que são apresentadas quando pretendemos obter informação acerca do objecto.

Para além deste PropertySet, ainda existem outros com signficado especial:

  • DefaultDisplayProperty: define a propriedade usada para apresentar os headers (elemento do tipo NoteProperty).
  • DefaultKeyPropertySet: indica qual a propriedade que deve ser usada na ordenação dos objectos (elemento do tipo PropertySet).

Finalmente, podemos ainda recorrer a elementos do tipo <CodeMethod>, colocados no interior de cada elemento <Type>, para definirmos métodos associados ao tipo. Por exemplo,  a entrada seguinte configura a classe System.Xml.XmlNode de forma a garantir que todas as invocações do método ToString são redireccionadas para o método XmlNode exposto pela classe System.Management.Automation.ToStringCodeMethods:

<Type>
        <Name>System.Xml.XmlNodeList</Name>
        <Members>
            <CodeMethod>
                <Name>ToString</Name>
                <CodeReference>
                    <TypeName>System.Management.Automation.ToStringCodeMethods</TypeName>
                    <MethodName>XmlNodeList</MethodName>
                </CodeReference>
            </CodeMethod>
        </Members>
    </Type>

Se quisermos, podemos criar as nossas próprias extensões. Para tal, temos apenas de criar um novo ficheiro .mshxml e importar essa informação para a shell (é importante salientar que nunca devemos alterar o ficheiro predefinido types.mshxml). Após criarmos o nosso ficheiro, devemos importá-lo através da utilização do cmdlet update-typedata. O cmdlet possui dois parâmetros que definem o processamento aplicado ao ficheiro personalizado .mshxml:

  • AppendPath: a utilização deste parâmetro faz com que o ficheiro seja adicionado à lista de ficheiros a carregar. Neste caso, o ficheiro será apenas tratado após a conclusão do processamento dos ficheiros standard.
  • PrependPath: semelhante ao anterior, mas neste caso os ficheiros indicados são tratados antes dos ficheiros standard normalmente carregados pela shell.

Refira-se que ambos os parâmetros recebem um array de strings, pelo que podemos carregar vários ficheiros simultaneamente. Para demonstrar a importação destas definições, vamos começar por criar um ficheiro mshxml muito simples:

<Types>
    <Type>
        <Name>System.Array</Name>
        <Members>
            <AliasProperty>
                <Name>Contagem</Name>
                <ReferencedMemberName>Length</ReferencedMemberName>
            </AliasProperty>
        </Members>
    </Type>
</Types>

Como é possível verificar, o ficheiro define apenas um alias, designado de Contagem, que retorna o número de elementos do array. A mportação desta informação pode ser feita através do seguinte comando:

MSH c:\>update-typedata -appendpath mytypes.mshxml

Em seguida, podemos excutar os seguintes comandos:

MSH c:\>$a=(1,2)

MSH c:\>$a.Contagem
2

E por hoje é tudo! No próximo post, vou falar um pouco acerca das várias opções de formatação disponibilizadas pelo Monad.

posted on Thursday, March 23, 2006 11:46 AM
Comments
No comments posted yet
Title  
Name  
Url
Box Code
Protected by FormShield
Comments