Considerações ao Reexecutar Transformações UML-para-C#

A transformação UML-para-C# inclui a tag @generated em determinados elementos gerados. Quando você reexecuta uma transformação, ela sobrescreve elementos específicos que têm uma tag @generated. Para proteger as alterações que são feitas no código gerado, é necessário remover instâncias específicas da tag @generated. Para representar elementos C# que não podem ser modelados, inclua código nas seções definidas pelo usuário na saída da transformação.

Elementos Gerados pela Transformação

A transformação UML-para-C# inclui a tag @generated nos seguintes elementos:

Protegendo o Código Gerado

Quando você reexecuta uma transformação UML-para-C#, por padrão, a transformação não sobrescreve corpos de métodos gerados por ela ou criados por um usuário. A transformação sempre preserva os corpos de métodos, independentemente se você remover, ou não, a tag @generated.

Se a tag @generated não for removida dos elementos a seguir, a transformação os sobrescreverá, independentemente se eles forem de nível mais alto ou aninhados:
  • Classes
  • Estruturas
  • Enumerações
  • Delegações
  • Campos
  • Métodos
  • Propriedades

Embora a transformação sempre preserve os corpos de métodos, a tag @generated deve ser removida de um método para preservar as alterações estruturais no método. Por exemplo, você deverá remover a tag @generated do método se alterar a assinatura de método, incluir inicializadores em um construtor, incluir exceções em métodos ou incluir comentários no código-fonte.

Se você não remover a tag @generated, a transformação sobrescreverá os elementos aos quais a tag @generated se aplica. A transformação também sobrescreve os seguintes elementos:
  • Palavras-chave
  • Membros de classes
  • Parâmetros
Nota: Para incluir o método no modelo UML de origem, execute a transformação reversa.

Protegendo o Novo Código

Qualquer código que você inserir em artefatos de origem gerados e não gerados pode ser protegido contra substituição de sucessivas transformações reversas e de encaminhamento, se o código for ou não reconhecido no UML. Por exemplo, as diretivas pré-processador C# não são reconhecidas, mas são preservadas. Os seguintes tipos de elemento ou áreas de código de usuário são protegidos:
  • Atributos e tipos aninhados
  • Seções definidas pelo usuário em cada arquivo de origem
  • Seções de código pré e pós usuário ao redor de tipos gerados e membros de tipo
A transformação não sobrescreve atributos, classes aninhadas, estruturas ou enumerações que você inclui no código C#, a não ser que a tag @generated seja incluída por engano nesses elementos.
Nota: Para incluir atributos, classes aninhadas, estruturas ou enumerações no modelo UML de origem, execute a transformação reversa.

Também é possível incluir código criado pela transformação nas seções definidas pelo usuário. A transformação não sobrescreve ou remove código que você especifica em uma seção definida pelo usuário.

A transformação gera seções definidas pelo usuário em arquivos de código. A transformação inclui uma seção definida pelo usuário no início de cada um desses arquivos. Você pode utilizar essa seção para especificar parâmetros using.
Nota: Você não deve digitar nenhum tipo na seção definida pelo usuário. Ela é utilizada apenas para declarar instruções using.
Outra maneira de preservar código de usuário é obter vantagem de seções pré e pós código do usuário. Essas seções existem ao redor dos seguintes elementos C# gerados:
  • Membros de tipo - incluindo campos, métodos, delegados e eventos
  • Declarações de tipo compostos - incluindo classes, estruturas e interfaces
  • Delegações
  • Enumerações
  • Espaços de nome

Qualquer código de usuário que você inserir diretamente após qualquer um desses elementos listados acima, sem nenhuma linha em branco para intervir, é interpretado por uma transformação como o pós código de usuário do elemento diretamente antes dele. Todo código de usuário que você inserir após uma linha em branco é interpretado por uma transformação como o código pré usuário para o elemento sucessor.

Embora a tag @generated e as seções definidas pelo usuário, de pré código de usuário e de pós código de usuário ofereçam flexibilidade, para evitar possíveis problemas, você deve fazer alterações estruturais no modelo UML de origem em vez do código gerado. Também é possível executar a transformação reversa para incluir novos métodos ou atributos no modelo UML de origem.

Exemplos de Implementações de Pré e Pós Código de Usuário

Algumas variações de implementação de pré e pós código de usuário existem para elementos, espaços de nomes e comentários típicos.

Elementos típicos

Considere o seguinte fragmento de código:

#if DEBUG
 // @generated
 // @C#_transform [
 // _URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_KBkvkMtZEd2IB4RiswwPkg
 // ]
 public void Operation1() {
  //TAREFA A FAZER: stub de método gerado automaticamente
  throw new System.NotImplementedException();
 }
#endif

 // @generated
 // @C#_transform [
 // _URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_UxwLEc2-Ed2itJx87rzLyg
 // ]
 public void Operation2() {
  //TAREFA A FAZER: stub de método gerado automaticamente
        throw new System.NotImplementedException();
 }

No exemplo acima, a diretiva #endif é a seção de pós código de usuário do elemento Operation1. Se não existirem linhas em branco entre dois elementos, todo o código a partir do final do primeiro elemento para @generated, @C#_transform [, ou do início do próximo elemento é considerado como pós código do usuário do primeiro elemento. Uma exceção à regra de delimitação de espaço é se houver um espaço após em elemento seguido por código de usuário, mas não existir elementos adicionais, então o código do usuário é anexado como pós código do usuário do elemento precedente, como no exemplo a seguir:

public class Class1 {

         // @generated
        // @C#_transform [
 // _URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_KBkvkMtZEd2IB4RiswwPkg
        // ]
        public void Operation1() {
           //TAREFA A FAZER: stub de método gerado automaticamente
          throw new System.NotImplementedException();
       }
 
      // @generated
      // @C#_transform [
      // _URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_UxwLEc2-Ed2itJx87rzLyg
      // ]
      public void Operation2() {
          //TAREFA A FAZER: stub de método gerado automaticamente
         throw new System.NotImplementedException();
       }
 
#endif
}

Espaços de nomes e instruções #define

Os elementos dentro de um espaço de nomes podem ser divididos, ou mesclado com elementos do mesmo espaço de nomes, entre unidades de compilação. Como um princípio geral, se uma declaração de tipo composto, enumeração ou delegado dentro de um espaço de nomes for movida para outra unidade de compilação, por exemplo, usando modelos de mapeamento, o elemento transporta o código do usuário do espaço de nomes integrado da unidade de origem para o espaço de nomes na unidade de destino, e o anexa ao código de usuário existente no destino.

Considere o seguinte código de amostra para Class1.cs:

public class Class1 {
}

#region com-Class1
namespace com
{
	public class Class3
{
}


public class Class4
{
}
}
#endregion

Class2.cs:
public class Class2
{
}

#region com-Class2
namespace com
{
	public class Class5
{
}
}
#endregion

Se você modificar o modelo de mapeamento para que com.Class4 seja movido para Class2.cs, o código resultante após uma transformação de encaminhamento seria gerado como o exemplo a seguir:

Class1.cs

public class Class1 {
}

#region com-Class1
namespace com
{
	public class Class3
{
}

}
#endregion

Class2.cs

public class Class2
{
}

#region com-Class2
#region com-Class1
namespace com
{

public class Class4
{
}


	public class Class5
{
}
}
#endregion
#endregion

Os elementos de pré e pós código de usuário#region com-Class1 e #endregion são incluídos no código de usuário existente pela transformação. Note que o pré código de usuário está anexado enquanto que o pós código de usuário está prefixado.

Da mesma forma, quando uma declaração de tipo composto ou espaço de nomes é movida de uma unidade de compilação para outra através de modelos de mapeamento, as instruções #define e #undef da unidade de origem são anexadas na unidade de destino.

Comentários

Comentários que estão localizados acima de uma diretiva de pré-processador são considerados relevantes a ele, e também são preservados como código de usuário. A ordem de comentários e diretivas de pré-processador é mantida. Considere o seguinte fragmento de código:

// @generated
// @C#_transform [
//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_0o-fIOhIEd2SdrLLRilfrw
//	]
public class Class1 {

	#region c
	// @generated
	// @C#_transform [
	//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_S4TRgOkaEd2owca4Ri32gw
	//	]
	public void Operation2() {
		//TAREFA A FAZER: stub de método gerado automaticamente
		throw new System.NotImplementedException();
	}
//region ends
#endregion



    
//comment for a
    #region a
    //comment for b
    #region b

	// @generated
	// @C#_transform [
	//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_vZgVUOhjEd2vc-H9Qq-k_Q
	//	]
	public void Operation1() {
		//TAREFA A FAZER: stub de método gerado automaticamente
		throw new System.NotImplementedException();
	}
//end b
    #endregion
    //end a
    #endregion

}

O código de após Operation2() até a diretiva #endregion é designado como pós código de usuário para o método. Após a ocorrência de uma linha em branco, tudo a partir dali até a última diretiva do pré-processador é designado como pré código de usuário para Operation1(). Note que isso também inclui comentários. O pré código de usuário terá o comentário //region ends e o pós código de usuário terá os comentários //comment for a e //comment for b. Isso preserva quaisquer comentários relevantes às diretivas.

A documentação UML pertencente à transformação e propriedades de modelo é armazenada como código de usuário. Em vez disso, a documentação UML é armazenada no modelo. Se as diretivas do pré-processador estão incluídas como elementos não modelados, quando você reaplicar uma transformação, a documentação é preservada para todos os elementos não modelados, enquanto que a documentação para elementos modelados é obtida da guia Documentação no modelo.

Limitação na Funcionalidade da Preservação do Código

Quando você executar novamente a transformação UML em C# após incluir código às seções de código pré e pós usuário, a transformação reordenará determinados elementos no código de origem.

Por exemplo, se o seguinte fragmento de código que foi gerado pela transformação de UML em C#, um desenvolvedor de software incluiu um atributo denominado attribute1 entre Operation2() e Operation1().

// @generated
// @C#_transform [
//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_GXpy8Nr5Ed2zKbxEG_6cmQ
//	]
public class Class2
{

	// @generated
	// @C#_transform [
	//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_tnNPwNsGEd2zKbxEG_6cmQ
	//	]
	public void Operation2() {
		//TAREFA A FAZER: stub de método gerado automaticamente
		throw new System.NotImplementedException();
	}

#if DEBUG
    // @generated
    // @C#_transform [
    //	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_HEXH8Nr5Ed2zKbxEG_6cmQ
    //	]
    private Object attribute1;


	// @generated
	// @C#_transform [
	//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_HYxRsNr5Ed2zKbxEG_6cmQ
	//	]
	public void Operation1() {
		//TAREFA A FAZER: stub de método gerado automaticamente
		throw new System.NotImplementedException();
	}
#endif

}

Quando o desenvolvedor executar novamente a transformação de UML em C#, o atributo denominado attribute 1 se move para a parte superior do código, juntamente com o pré código de usuário anexado. O código modificado então se parecerá com o seguinte exemplo:

// @generated
// @C#_transform [
//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_GXpy8Nr5Ed2zKbxEG_6cmQ
//	]
public class Class2
{


#if DEBUG
	// @generated
	// @C#_transform [
	//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_HEXH8Nr5Ed2zKbxEG_6cmQ
	//	]
	private Object attribute1;



	// @generated
	// @C#_transform [
	//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_tnNPwNsGEd2zKbxEG_6cmQ
	//	]
	public void Operation2() {
		//TAREFA A FAZER: stub de método gerado automaticamente
		throw new System.NotImplementedException();
	}



	// @generated
	// @C#_transform [
	//	_URI=platform:/resource/GraphicsLibraryProject/GraphicsModel.emx#_HYxRsNr5Ed2zKbxEG_6cmQ
	//	]
	public void Operation1() {
		//TAREFA A FAZER: stub de método gerado automaticamente
		throw new System.NotImplementedException();
	}
#endif

}

A reordenação de elementos muda o resultado do pré-processador, como o loop “#if” no exemplo acima e pode causar erros de compilação. O desenvolvedor deve estar ciente de que a funcionalidade de preservação do código é imprevisível se você reordenar os elementos manualmente.


Feedback