Método concisa para Passando associativa matrizes para o método
-
22-08-2019 - |
Pergunta
Procurando uma maneira de passar uma matriz associativa para um método. Eu estou olhando para reescrever um pacote de Tween Actionscript em C #, mas correndo em problemas com "associativos" matrizes / objetos. Normalmente, em Actionscript eu poderia fazer algo como:
public function tween(obj:DisplayObject, params:Object = null):void {
if (params.ease != null) {
//do something
}
//...
}
E este poderia ser chamado como:
tween(this, {ease:'out', duration:15});
Eu estou procurando uma maneira de fazer o mesmo em C #. Até agora, eu recolhi minhas opções a ser:
a) a criação de uma classe ou struct para definir as teclas param e tipos possíveis e passar essa
b) passar os parâmetros como tipo genérico
tween(frameworkElement, new {ease = 'out', duration = 15});
assumindo
public static void tween(FrameworkElement target, object parameters);
e descobrir uma maneira de usar que na função de interpolação (não tenho certeza como separar a chave = valor do dado esse objeto. Alguma idéia?)
c) criar uma Dictionary<string, object>
para passar os parâmetros para a função de interpolação
Quaisquer outras idéias ou código de exemplo? Eu sou novo para C #.
Editar
Tomou-me todos os dias para descobrir isso:
"tipos anônimos não podem ser compartilhados além das fronteiras de montagem. Os garante compilador que existe no máximo um tipo anônimo para uma determinada sequência de pares nome de propriedade / tipo dentro de cada montagem. Para passar estruturas entre os conjuntos você precisará defini-los corretamente . "
Solução
Editar : Este é basicamente o mecanismo que HtmlHelper extensões usar em ASP.NET MVC. Não é original com mim.
Eu favorecer uma abordagem híbrida que tem duas assinaturas diferentes. Nota: Eu não tentei isso e pode haver um conflito entre as duas assinaturas para que você pode ter que dar o segundo método um nome ligeiramente diferente para permitir que o compilador para escolher entre eles, mas eu não penso assim.
public static void tween( FrameworkElement target, object parameters )
{
return tween( target, new ParameterDictionary( parameters ) );
}
public static void tween( FrameworkElement target,
ParameterDictionary values )
{
if (values.ContainsKey( "ease" ))
{
....
}
}
Em seguida, você tem uma classe ParameterDictionary que usa a reflexão sobre o tipo anônimo e configura o dicionário.
public class ParameterDictionary : Dictionary<string,object>
{
public ParameterDictionary( object parameters )
{
if (parameters != null)
{
foreach (PropertyInfo info in parameters.GetType()
.GetProperties())
{
object value = info.GetValue(parameters,null);
this.Add(info.Name,value);
}
}
}
}
Isto dá-lhe tanto a facilidade de uso e facilidade de consumo - o "feio" coisas reflexão é embrulhado em um único construtor para o dicionário, em vez de em seu método. E, claro, o dicionário pode ser usado repetidas vezes para fins semelhantes com o código de reflexão escrita apenas uma vez.
Outras dicas
O dicionário é uma abordagem razoável. Ele pode ter esta aparência:
public static void tween(FrameworkElement target, IDictionary<string, object> parameters)
{
if (parameters.ContainsKey("ease")) {
//do something
}
}
mente que quando você passar os valores na sintaxe coleção de inicialização, você pode usar encurtado para torná-lo mais fácil, como:
tween(something, new Dictionary<string, object> { { "ease", "out" }, { duration, 15 } });
Esta seria uma maneira muito rápida de fazer mais ou menos "a mesma coisa", como o código ActionScript, mas não é realmente grande C #. A C # forma -ish de fazê-lo seria fazer um TweenParameters struct real ou classe com propriedades de cada parâmetro possível, e, em seguida, criar um para passar para o tween (). Este é geralmente considerado mais sustentável, uma vez que todas as propriedades "disponíveis" são óbvias para um chamador sem olhar para os internos do Tween (), e porque ele pega erros em tempo de compilação que uma comparação de string não seria aviso prévio até a execução, como typoing "duração" "duratoin".
Eu sou um fã de opção (b) me - passando um tipo anônimo e analisar os valores usando a reflexão
.Eu vi os outros a alcançar a mesma coisa usando expressões lambda. A sintaxe chamar seria:
tween(frameworkElement, ease => "out", duration => 15);
E a declaração seria algo ao longo das linhas de:
public static void tween(FrameworkElement target, params Expression<Func<object>>[] parameters) { ... }
A idéia é que você pode ter um número variável de "funções que retornam objeto". Você, então, analisar o nome do parâmetro de saída de cada Expression
Eu não acho que isso é melhor do que refletir sobre um tipo anônimo, mas é uma outra abordagem para considerar.
Atualizar
Eu tenho realmente escrito sobre a idéia de passar arrays associativos como dicionários no meu blog, aqui e aqui .