XmlSerializer possui erro com Array de List

Um erro desses deve afetar poucas pessoas, mas na versão atual do .NET Framework 4.5.1 ocorre um erro de object reference ao executar o codigo a seguir:

       XmlSerializer serializaer = new XmlSerializer(typeof(List<string>[]));

Ao executar esse codigo ocorre um erro do tipo System.NullReferenceException, seguindo o Stack ocorre no metodo System.Xml.Serialization.CodeGenerator.GetVariableType. O Stack Completo do erro é assim:

 

at System.Xml.Serialization.CodeGenerator.GetVariableType(Object var)
at System.Xml.Serialization.SourceInfo.InternalLoad(Type elementType, Boolean asAddress)
at System.Xml.Serialization.XmlSerializationILGen.ILGenLoad(String source, Type type)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberBegin(Member[] members)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteArray(String source, String arrayName, ArrayMapping arrayMapping, Boolean readOnly, Boolean isNullable, Int32 fixupIndex, Int32 elementIndex)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteElement(String source, String arrayName, String choiceSource, ElementAccessor element, ChoiceIdentifierAccessor choice, String checkSpecified, Boolean checkForNull, Boolean readOnly, Int32 fixupIndex, Int32 elementIndex)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberElementsIf(Member[] members, Member anyElement, String elementElseString)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberElements(Member[] members, String elementElseString, String elseString, Member anyElement, Member anyText)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteArray(String source, String arrayName, ArrayMapping arrayMapping, Boolean readOnly, Boolean isNullable, Int32 fixupIndex, Int32 elementIndex)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteElement(String source, String arrayName, String choiceSource, ElementAccessor element, ChoiceIdentifierAccessor choice, String checkSpecified, Boolean checkForNull, Boolean readOnly, Int32 fixupIndex, Int32 elementIndex)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberElementsIf(Member[] members, Member anyElement, String elementElseString)
at System.Xml.Serialization.XmlSerializationReaderILGen.WriteMemberElements(Member[] members, String elementElseString, String elseString, Member anyElement, Member anyText)
at System.Xml.Serialization.XmlSerializationReaderILGen.GenerateTypeElement(XmlTypeMapping xmlTypeMapping)
at System.Xml.Serialization.XmlSerializationReaderILGen.GenerateElement(XmlMapping xmlMapping)
at System.Xml.Serialization.TempAssembly.GenerateRefEmitAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence)
at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence)
at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type)
at MeuPrograma.Program.Main(String[] args) in d:\MeuPrograma\Program.cs:line 47
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

Porém encontrar o erro assim é muito simples, mas a serialização de XML como mostrada é utilizada em diversos outros lugares como WebAPI e WebServices(Asmx). No meu caso encontrei esse erro em um Asmx graças a esse link(que está em Frances) consegui identificar que um metodo estava retornar um objeto com Array de Lista e foi identificado o problema. Não é permitido utilizar array de List como parametro ou retorno de metodos ASMX pois pode ocrrer esse problema na serialização do cliente.

Para resolver esse problema a unica possibilidade é transformar este Array de List em um Objeto, ficando até mais organizado, ou se quiser deixar porcamente pode ser utilizado um List de List que o XmlSerializer vai funcionar.

Anúncios

Definir Parametro generico por tipo(type)

Falando sobre reflection um necessidade que encontrei e vou colocar aqui é definir um parametro generico de uma classe por um Type, para isso podemos usar o metodo MakeGenericType. O conteudo é bem simples então vou apenas postar o codigo de como fazer sem muita necessidade de explicação.

            Type typeGenericList = typeof(MyClass);
            var ListWithoutType = typeof(IList<>); // this is a list generic without the generic type set
            var ListWithType = ListWithoutType.MakeGenericType(tipoEntidade); // this is a list generic with the generic parametier of MyClass IList<MyClass>

Como descobrir o tamanho de um arquivo

Para descobrir o tamanho  de um arquivo com C# basta utilizar a classe FileInfo, e utilizar a propriedade Length que retorno o tamanho em bytes do arquivo, ai basta dividir por 1024 quantas vezes precisar para ter o tamanho na proporção que precisa, esse e um exemplo do calculo ate GB:

FileInfo fi =new FileInfo("nomeArquivo.doc");
 var TamanhoEmKb = (fi.Length/1024F);
 var TamanhoEmMb = ((fi.Length/1024F)/1024F);
 var TamanhoEmGb = (((fi.Length/1024F)/1024F)/1024F);

Como copiar o conteudo de uma Stream para outra

Em alguns casos é necessário copiar o conteudo de uma Stream para outra Stream. Se voce apenas atribuir para uma nova variavel não será criada uma nova variavel e sim ter mais uma referencia para a mesma variavel em memoria(se não conseguiu leia esse post).
Voltando para o nosso problema, para copiar o conteúdo de uma stream para outra efetuei a chamada para esse método passando a stream que contem o conteúdo que deseja copiar no parâmetro src e passe a stream que deseja receber esse conteúdo. Segue o método para utilizar:

public static void CopyTo(System.IO.Stream src, System.IO.Stream dest)
 {

int readCount;

var buffer = new byte[8192];
while ((readCount = src.Read(buffer, 0, buffer.Length)) != 0)
dest.Write(buffer, 0, readCount);
 }

Quando salva um arquivo ocorre o erro “Illegal characters in path.”

Quando uma aplicação precisa salvar um arquivo, ou criar uma pasta que o usuário define o nome ou depende de algo que um usuário preenche é necessário um certo cuidado com esses dados pois dependendo da informação que o usuário coloca pode ocorrer o erro “Illegal characters in path.”.

Para evitar isso é necessário toda vez que for salvar um arquivo executar uma rotina parecida com essa:

public static string RemoverCaracteresInvalidosArquivo(string path)
 {

if (path.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) >= 0)
{
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
path = path.Replace(c.ToString(), string.Empty);
}
}

return path;

}

Neste caso é tirado esse carácter e substituído por uma string vazia, mas é possível fazer trocando os valores por um valor qualquer.

Extension Methods

Definição:Métodos extensores para criação de métodos em determinado tipo de Objeto, Interface ou enumerado, não obrigando a ter o fonte do objeto que será extendido.O Conceito de extension methods surgiu junto com LINQ, na versão 3.5 do framework, foi criado devido a necessidade da microsoft colocar metodos em determinadas interfaces, um exemplo é os metodos LINQ(Where, Select ou Join) eles são extension methods da interface IEnumareble<T>.Ao Criar um metodo de extensão em um tipo e esse tipo já possui um metodo com a mesma assinatura, o metodo de extensão não será utilizado, será utilizado o metodo real do tipo.

A ideia é muito simples, criar metodos para um determinado tipo independente da origem do tipo em questão.

Na Pratica: Aonde isso irá me ajudar no trabalho do dia-a-dia correto? Uma aplicação Simples é utilizar para validar o conteúdo de um controle por exemplo:

  • Em um TextBox você poderia colocar o metodo IsEmpty() que iria verificar se o conteúdo do TextBox é vazio, ou o método IsNumber() no mesmo TextBox para validar se o conteúdo é apenas numérico.
  • Em um enumerado qualquer é possivel colocar um metodo para um objeto a partir do valor do enumerado.
Codificação:
Crie uma classe publica estática( precisa ser estática) e adiciona um método estático normalmente, porem adicionar a palavra this no primeiro parâmetro indicando de qual tipo será essa extensão, segue o codigo exemplificado:

 public static class Extensions
    {
        public static bool EhPar(this int numero)
        {
            return numero % 2 == 0;
        }

        public static bool EhImpar(this int numero)
        {
            return numero % 2 != 0;
        }
    }

Os métodos irão aparecer nos objetos desse tipo, nesse caso em qualquer int igual na imagem

Como ira ficar na IDE

Código de exemplo de utilização dos métodos


            int par = 3;
            bool IsImpar = par.EhImpar();
            bool IsPar = par.EhPar();