sexta-feira, 9 de outubro de 2009

Personalizando o toString em enums

Os enumerados são, sem dúvida, grandes ferramentas para auxiliar e padronizar o desenvolvimento de aplicativos. Eu, por exemplo, o considero excelente para sumir com os famosos números mágicos (magic numbers) dentro das entidades, ex:


//Antes
productionOrder.State = 3;
//Depois
productionOrder.State = ProductionOrderState.Canceled;

Porém, uma desvantagem do enum é quando você quer exibir o texto do valor contido no enum. Ex.:
ProductionOrderState productionOrderState = ProductionOrderState.Canceled;
Console.Writeline(productionOrderState);
//Print: Canceled


Como fazer para imprimir "Production Order is Canceled" no lugar de Canceled?
Abaixo vai uma dica bem simples de como fazer isso. Primeiro copie o código abaixo:
public struct Described<T> where T : struct
{

private T _value;

public Described(T value)
{
_value = value;
}

public override string ToString()
{
string text = _value.ToString();
object[] attr = typeof(T).GetField(text).GetCustomAttributes(typeof(DescriptionAttribute), false);

if (attr.Length == 1)
text = ((DescriptionAttribute)attr[0]).Description;

return text;
}

public static implicit operator Described<T>(T value)
{
return new Described<T>(value);
}

public static implicit operator T(Described<T> value)
{
return value._value;
}
}
Fonte: Post StackOverFlow (http://stackoverflow.com/questions/796607/how-do-i-override-tostring-in-c-enums)
Agora no seu enum implemente o atributo Description, do namespace System.ComponentModel em cada item do enum:
public enum ProductionOrderState
{
[Description("Production Order is Open")]
Open,
[Description("Production Order is Canceled")]
Canceled
}

Para obter a descrição do valor do enum faça o seguinte:
Described<ProductionOrderState> status = ProductionOrderState.Open;
Console.WriteLine(status);
//Print: Production Order is Open

Veja que a classe Described não influencia em nada o funcionamento do enum, veja o teste abaixo:

Described<ProductionOrderState> status = ProductionOrderState.Open;
Console.WriteLine(status);
ProductionOrderState other = status;
Console.WriteLine(other);

Mas ainda não é o suficiente certo? A descrição esta hard code como vamos fazer quando tiver que alterar a descrição? E para multi idioma como ficaria?

Para resolver esse problema crie um Resource no seu projeto e coloque nele as descrições que precisa para o seu enum.

resource

Para obter o valor do Resource nos items do enum podemos utilizar uma classe disponível no Enterprise Library (http://msdn.microsoft.com/en-us/library/cc467894.aspx), faça referência no seu projeto a dll Microsoft.Practices.EnterpriseLibrary.Configuration.Design, dentro dela você contará com o atributo SRDescription.

Troque no seu enum o attribute Description pelo SRDescription informando o nome do Resource que você criou e o nome da chave do resource que você criou, ex:
public enum ProductionOrderState
{
[SRDescription("Sts_Open", typeof(Resources))]
Open,
[SRDescription("Sts_Canceled", typeof(Resources))]
Canceled
}

Prontinho, agora temos disponível um meio prático de obter e personalizar as descrições dos nossos enums.

Nenhum comentário: