terça-feira, julho 20, 2010

O Pequeno Mistério do System.String.Contains no .NET

Estou trabalhando atualmente em um aplicativo ASP.Net (usando Web Forms), adaptando o código de um outro aplicativo que eu fiz algum tempo atrás. Entre as várias surpresas, um pequeno mistério.

Ao codificar uma página, surgiu a necessidade de verificar se um string continha o caracter '*'. Uma rápida olhada nos métodos apresentados pelo IntelliSense levou ao uso da função Contains:
string valor;
if (valor.Contains('*'))
{
// etc..
}
Abaixo a ajuda apresentada pelo Help do Visual Studio (pressionando F1 sobre a palavra Contains no código acima):

Ajuda para System.String.Contains - clique para ampliar.

Compilei, testei e tudo funcionou.

Um pouco mais adiante, ao programar uma outra página, percebi que o código onde era usado o Contains poderia ser re-utilizado. Resolvi então movê-lo para uma outra classe que já existia em um outro fonte. Na hora de compilar, a surpresa: erro de sintaxe - Contains não aceita um parâmetro do tipo Char.

Pressionando F1, uma outra tela de ajuda é apresentada:

String.Contains agora requer um string como parâmetro - clique para ampliar.

Está aí um pequeno mistério: como um código que compilou e executou corretamente em um módulo fonte dá erro de sintaxe em outro?

Após um bom tempo quebrando a cabeça, reparei que existem duas definições de Contains na classe System.String. A primeira está nos métodos "normais":

A versão com parâmetro String é um método de System.String - clique para ampliar.

Já a segunda definição está nos "Extension Methods", métodos herdados da classe "pai" ou das interfaces que System.String implementa:

A versão com parâmetro Char é um "Extension Methods" - clique para ampliar.

Voltando à primeira figura, está escrito lá que Contains(Char) é definido em Enumerable. A página de ajuda de Enumerable traz a última pista para o mistério:

Algumas informações sobre Enumerable - clique para ampliar.

A versão que aceita Char está definida no namespace System.Linq e disponível a partir do .Net Framework 3.5. Estou atualmente usando o Visual Studio 2008 e ele coloca automaticamente "using System.Linq" ao criar o código de uma página, já que optei por usar o .Net Framework 3.5. Já o módulo para o qual eu tinha movido o código tinha sido criado com o Visual Studio 2005, usando o .Net Framework 2.0.

Bastou colocar o "using System.Linq" no fonte antigo para o compilador reconhecer o Using(Char). Fim do mistério.

Nenhum comentário: