Eu tenho esta função de API:
public ResultEnum DoSomeAction(string a, string b, DateTime c, OtherEnum d,
string e, string f, out Guid code)
Eu não gosto disso Porque a ordem dos parâmetros se torna desnecessariamente significativa. Torna-se mais difícil adicionar novos campos. É mais difícil ver o que está sendo repassado. É mais difícil refatorar o método em partes menores, porque isso cria outra sobrecarga na passagem de todos os parâmetros nas sub-funções. O código é mais difícil de ler.
Tive a idéia mais óbvia: ter um objeto encapsulando os dados e repassá-los ao invés de passar cada parâmetro um por um. Aqui está o que eu vim com:
public class DoSomeActionParameters
{
public string A;
public string B;
public DateTime C;
public OtherEnum D;
public string E;
public string F;
}
Isso reduziu minha declaração da API para:
public ResultEnum DoSomeAction(DoSomeActionParameters parameters, out Guid code)
Agradável. Parece muito inocente, mas na verdade introduzimos uma grande mudança: introduzimos a mutabilidade. Porque o que estávamos fazendo anteriormente era realmente passar um objeto imutável anônimo: parâmetros de função na pilha. Agora criamos uma nova classe que é muito mutável. Criamos a capacidade de manipular o estado do chamador . Isso é péssimo. Agora eu quero meu objeto imutável, o que faço?
public class DoSomeActionParameters
{
public string A { get; private set; }
public string B { get; private set; }
public DateTime C { get; private set; }
public OtherEnum D { get; private set; }
public string E { get; private set; }
public string F { get; private set; }
public DoSomeActionParameters(string a, string b, DateTime c, OtherEnum d,
string e, string f)
{
this.A = a;
this.B = b;
// ... tears erased the text here
}
}
Como você pode ver, eu realmente recriei meu problema original: muitos parâmetros. É óbvio que esse não é o caminho a seguir. O que eu vou fazer? A última opção para alcançar essa imutabilidade é usar uma estrutura "somente leitura" como esta:
public struct DoSomeActionParameters
{
public readonly string A;
public readonly string B;
public readonly DateTime C;
public readonly OtherEnum D;
public readonly string E;
public readonly string F;
}
Isso nos permite evitar construtores com muitos parâmetros e obter imutabilidade. Na verdade, ele corrige todos os problemas (ordenação de parâmetros etc.). Ainda:
- Todos (incluindo FXCop e Jon Skeet) concordam que a exposição de campos públicos é ruim .
- Eric Lippert e colaboradores afirmam que confiar em campos somente para imutabilidade é uma mentira .
Foi quando fiquei confuso e decidi escrever esta pergunta: Qual é a maneira mais direta em C # de evitar o problema de "muitos parâmetros" sem introduzir mutabilidade? É possível usar uma estrutura somente leitura para esse fim e ainda não ter um design de API ruim?
ESCLARECIMENTOS:
- Por favor, assuma que não há violação do princípio de responsabilidade única. No meu caso original, a função apenas grava parâmetros fornecidos em um único registro de banco de dados.
- Não estou procurando uma solução específica para a função especificada. Estou buscando uma abordagem generalizada para esses problemas. Estou especificamente interessado em resolver o problema de "muitos parâmetros" sem introduzir mutabilidade ou um design terrível.
ATUALIZAR
As respostas fornecidas aqui têm diferentes vantagens / desvantagens. Portanto, eu gostaria de converter isso em um wiki da comunidade. Acho que cada resposta com amostra de código e Prós / Contras seria um bom guia para problemas semelhantes no futuro. Agora estou tentando descobrir como fazê-lo.
DoSomeActionParameters
é um objeto descartável, que será descartado após a chamada do método.