Implementações de uma estrutura “Point3” em C#, como era em 2002, como é em 2019

Voltemos no tempo. 2002!

using System;

namespace Foo
{
    class Program
    {
        static void Main(string[] args)
        {
            Point3F p = new Point3F(2, 3, 4);
            Console.WriteLine("The Point is " + p.ToString());
        }
    }

    public struct Point3F
    {
        public Point3F(float x, float y, float z)
        {
            _x = x;
            _y = y;
            _z = z;
        }
        
        private readonly float _x;
        public float X 
        {
            get 
            { 
                return _x; 
            }
        }

        private readonly float _y;
        public float Y 
        {
            get 
            {
                return _y;
            }
        }

        private readonly float _z;
        public float Z
        {
            get
            {
                return _z;
            }
        }

        public override string ToString() 
        {
            return string.Format("{0}; {1}; {2}", _x, _y, _z);
        }
    }
}

Agora, de volta para o presente. 2019!

using static System.Console;

namespace Foo
{
    class Program
    {
        static void Main(string[] args)
        {
            var p = new Point3<float>(2, 3, 4);
            WriteLine($"The Point is {p}");
        }
    }

    public readonly struct Point3<T>
    {
        public Point3(T x, T y, T z) =>
            (X, Y, Z) = (x, y, z);
      
        public T X { get; }
        public T Y { get; }
        public T Z { get; }

        public override string ToString() => $"{X}, {Y}, {Z}";
    }
}

Não é difícil perceber, olhando o código do exemplo, que hoje em dia é possível escrever muito menos código, com muito mais expressividade.

As auto-properties, por exemplo, retiraram a necessidade de criármos campos específicos, manualmente, para armazenar seus valores.  Na prática, os campos ainda são criados pelo compilador e, a propóstito, como as propriedades são somente leitura, os campos gerados pelo compilador também são.

Os expression bodied members também reduziram consideravelmente a quantidade de “{}” espalhadas pelo código e tornaram a leitura do código mais rápida.

A possibilidade de declarar o uso de uma classe estática, com using static, para acesso direto a seus membros também torna o código mais limpo, embora, um pouco estranho a primeira vista..

As interpolações de string deram mais fluência para as contatenações.

Por fim, como novidade no C# 8,  agora structs genéricas, quando usadas com parâmetros de tipo sendo tipos primitivos, são valores não gerenciados (unmanaged).

Bônus

A utilização de generics com structs, sem prejuizo de performance para parâmetros de tipos primitivos foi um grande avanço. Entretanto, infelizmente, ainda há desafios de generalização que precisam ser superados.

No código que compartilhamos acima, se precisássemos, por exemplo, calcular o “comprimento do vetor”, da origem até o ponto especificado, não teríamos como escrever uma constraint que facilitasse a generalização para numéricos, permitindo o uso simples de funções como Sqrt. A explicação para isso é dada pelo próprio Anders.

And it’s not clear that the added complexity is worth the small yield that you get. If something you want to do is not directly supported in the constraint system, you can do it with a factory pattern. You could have a Matrix, for example, and in that Matrix you would like to define a dot product method. That of course that means you ultimately need to understand how to multiply two Ts, but you can’t say that as a constraint, at least not if T is int, double, or float. But what you could do is have your Matrix take as an argument a Calculator, and in Calculator, have a method called multiply. You go implement that and you pass it to the Matrix.

Consideramos essa, uma abordagem “inteligente demais”. No mundo real, código “inteligente demais” é difícil de manter.

#nullable enable

using System;
using System.Collections.Generic;

using static System.Console;
using static System.Math;

namespace Foo
{
    class Program
    {
        static void Main(string[] args)
        {
            var p = new Point3<float>(3, 4, 0);
            WriteLine($"The Point is {p}. Length is {p.Length}");
        }
    }

    public readonly struct Point3<T>
    {
        private static readonly ILengthCalculator<T>? LengthCalculator = LengthCalculatorFactory.Of<T>();
        
        public Point3(T x, T y, T z) =>
            (X, Y, Z) = (x, y, z);
      
        public T X { get; }
        public T Y { get; }
        public T Z { get; }

        public override string ToString() => $"{X}, {Y}, {Z}";

        public double Length => LengthCalculator?.ComputeLength(X, Y, Z) ?? double.NaN;

    }

    public interface ILengthCalculator
    {
    };

    public interface ILengthCalculator<in T> : ILengthCalculator
    {
        double ComputeLength(T x, T y, T z);
    }

    public class LengthCalculatorForInt : ILengthCalculator<int>
    {
        public double ComputeLength(int x, int y, int z) => Sqrt(x * x + y * y + z * z);
    }

    public class LengthCalculatorForDouble : ILengthCalculator<double>
    {
        public double ComputeLength(double x, double y, double z) => Sqrt(x * x + y * y + z * z);
    }
    
    public class LengthCalculatorForFloat : ILengthCalculator<float>
    {
        public double ComputeLength(float x, float y, float z) => Sqrt(x * x + y * y + z * z);
    }
    
    public static class LengthCalculatorFactory
    {
        private static readonly Dictionary<Type, ILengthCalculator> Calculators
            = new Dictionary<Type, ILengthCalculator>()
            {
                {typeof(int), new LengthCalculatorForInt()},
                {typeof(float), new LengthCalculatorForFloat()},
                {typeof(double), new LengthCalculatorForDouble()},
            };
        
        public static ILengthCalculator<T>? Of<T>() 
            => (ILengthCalculator<T>) Calculators[typeof(T)];

    }
}

Se o desejo da Microsoft é adicionar suporte extendido para traits, por exemplo, a decisão de Anders, no passado, provavelmente terá de ser revista.

De qualquer forma, a inicialização do dicionário e o controle de propagação de nulls, mostradas no código, também foram grandes avanços da linguagem.

Compartilhe este insight:

Comentários

Participe deixando seu comentário sobre este artigo a seguir:

Subscribe
Notify of
guest
0 Comentários
Inline Feedbacks
View all comments

AUTOR

Elemar Júnior
Fundador e CEO da EximiaCo atua como tech trusted advisor ajudando empresas e profissionais a gerar mais resultados através da tecnologia.

NOVOS HORIZONTES PARA O SEU NEGÓCIO

Nosso time está preparado para superar junto com você grandes desafios tecnológicos.

Entre em contato e vamos juntos utilizar a tecnologia do jeito certo para gerar mais resultados.

Insights EximiaCo

Confira os conteúdos de negócios e tecnologia desenvolvidos pelos nossos consultores:

Arquivo

Pós-pandemia, trabalho remoto e a retenção dos profissionais de TI

CTO Consulting e Especialista em Execução em TI
EximiaCo 2024 - Todos os direitos reservados
0
Queremos saber a sua opinião, deixe seu comentáriox
()
x
Oferta de pré-venda!

Mentoria em
Arquitetura de Software

Práticas, padrões & técnicas para Arquitetura de Software, de maneira efetiva, com base em cenários reais para profissionais envolvidos no projeto e implantação de software.

Muito obrigado!

Deu tudo certo com seu envio!
Logo entraremos em contato

Implementações de uma estrutura “Point3” em C#, como era em 2002, como é em 2019

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Implementações de uma estrutura “Point3” em C#, como era em 2002, como é em 2019

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Condição especial de pré-venda: R$ 14.000,00 - contratando a mentoria até até 31/01/2023 e R$ 15.000,00 - contratando a mentoria a partir de 01/02/2023, em até 12x com taxas.

Tenho interesse nessa capacitação

Para solicitar mais informações sobre essa capacitação para a sua empresa, preencha o formulário a seguir:

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

O seu insight foi excluído com sucesso!

O seu insight foi excluído e não está mais disponível.

O seu insight foi salvo com sucesso!

Ele está na fila de espera, aguardando ser revisado para ter sua publicação programada.

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse nessa solução

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse neste serviço

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

× Precisa de ajuda?