Eu tenho vários métodos, todos com a mesma assinatura (parâmetros e valores de retorno), mas nomes diferentes e os elementos internos dos métodos são diferentes. Quero passar o nome do método para executar em outro método que invocará o método passado.
public int Method1(string)
{
... do something
return myInt;
}
public int Method2(string)
{
... do something different
return myInt;
}
public bool RunTheMethod([Method Name passed in here] myMethodName)
{
... do stuff
int i = myMethodName("My String");
... do more stuff
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
Este código não funciona, mas é isso que estou tentando fazer. O que não entendo é como escrever o código RunTheMethod, pois preciso definir o parâmetro.
Respostas:
Você pode usar o representante Func no .net 3.5 como o parâmetro no seu método RunTheMethod. O delegado Func permite especificar um método que utiliza vários parâmetros de um tipo específico e retorna um único argumento de um tipo específico. Aqui está um exemplo que deve funcionar:
fonte
Action
vez deFunc<string, int>
.Action<int,string>
corresponde a um método que utiliza 2 parâmetros (int e string) e retorna nulo.Func<double,string,int>
corresponde a um método que recebe 2 parâmetros (double
estring
) e retornaint
. O último tipo especificado é o tipo de retorno. Você pode usar esse delegado para até 16 parâmetros. Se você precisar de mais alguma coisa, escreva seu próprio representante comopublic delegate TResult Func<in T1, in T2, (as many arguments as you want), in Tn, out TResult>(T1 arg1, T2 arg2, ..., Tn argn);
. Por favor, corrija-me se eu entendi errado.Você precisa usar um delegado . Nesse caso, todos os seus métodos usam um
string
parâmetro e retornam umint
- isto é representado simplesmente peloFunc<string, int>
delegado 1 . Portanto, seu código pode se tornar correto com uma alteração tão simples quanto esta:Os delegados têm muito mais poder do que isso, é certo. Por exemplo, com C #, você pode criar um delegado a partir de uma expressão lambda , para poder invocar seu método da seguinte maneira:
Isso criará uma função anônima como esta:
e depois passe esse delegado para o
RunTheMethod
métodoVocê pode usar delegados para inscrições de eventos, execução assíncrona, retornos de chamada - todos os tipos de coisas. Vale a pena ler sobre eles, principalmente se você quiser usar o LINQ. Eu tenho um artigo que trata principalmente das diferenças entre delegados e eventos, mas você pode achar útil de qualquer maneira.
1 Isso se baseia apenas no
Func<T, TResult>
tipo de delegado genérico na estrutura; você pode facilmente declarar o seu:e faça com que o parâmetro seja do tipo
MyDelegateType
.fonte
public **delegate** int MyDelegateType(string value)
?Do exemplo do OP:
Você pode experimentar o Delegado de Ação! E então chame seu método usando
Ou
Em seguida, basta chamar o método
fonte
InvokeMethod
chamada lambda deve serRunTheMethod
em vezUso:
fonte
Por compartilhar uma solução o mais completa possível, vou apresentar três maneiras diferentes de fazer, mas agora vou começar pelo princípio mais básico.
Uma breve introdução
Todos os idiomas executados no CLR ( Common Language Runtime ), como C #, F # e Visual Basic, funcionam em uma VM, que executa o código em um nível superior aos idiomas nativos como C e C ++ (que são compilados diretamente na máquina). código). Daqui resulta que os métodos não são nenhum tipo de bloco compilado, mas são apenas elementos estruturados que o CLR reconhece. Portanto, você não pode passar um método como parâmetro, porque os métodos não produzem nenhum valor, pois não são expressões! Em vez disso, são instruções definidas no código CIL gerado. Então, você enfrentará o conceito de delegado.
O que é um delegado?
Um delegado representa um ponteiro para um método. Como eu disse acima, um método não é um valor, portanto, há uma classe especial nas linguagens CLR
Delegate
, que agrupa qualquer método.Veja o seguinte exemplo:
Três maneiras diferentes, o mesmo conceito por trás:
Caminho 1
Use a
Delegate
classe especial diretamente como no exemplo acima. O problema desta solução é que seu código será desmarcado quando você passar dinamicamente seus argumentos sem restringi-los aos tipos daqueles na definição do método.Caminho 2
Além do
Delegate
classe especial, o conceito de delegado se espalha para delegados personalizados, que são definições de métodos precedidos peladelegate
palavra - chave e se comportam da mesma forma que os métodos normais. Eles são verificados para que você tenha um código perfeitamente seguro.Aqui está um exemplo:
Caminho 3
Como alternativa, você pode usar um representante que já foi definido no .NET Standard:
Action
quebra umvoid
sem argumentos.Action<T1>
termina umvoid
com um argumento.Action<T1, T2>
envolve umvoid
com dois argumentos.Func<TR>
agrupa uma função com oTR
tipo de retorno e sem argumentos.Func<T1, TR>
agrupa uma função com oTR
tipo de retorno e com um argumento.Func<T1, T2, TR>
envolve uma função comTR
tipo de retorno e com dois argumentos.(A última solução é a que mais pessoas publicaram.)
fonte
Func<T1,T2,TR>
Você deve usar um
Func<string, int>
delegado, que representa uma função que recebe umstring
argumento as e retorna umint
:Então use-o:
fonte
Test
método deve serreturn RunTheMethod(Method1);
Se você quiser alterar o método chamado em tempo de execução, recomendo o uso de um representante: http://www.codeproject.com/KB/cs/delegates_step1.aspx
Isso permitirá que você crie um objeto para armazenar o método a ser chamado e você poderá transmiti-lo aos outros métodos quando necessário.
fonte
Embora a resposta aceita esteja absolutamente correta, eu gostaria de fornecer um método adicional.
Acabei aqui depois de fazer minha própria busca de uma solução para uma pergunta semelhante. Estou criando uma estrutura orientada a plug-ins e, como parte dela, queria que as pessoas pudessem adicionar itens de menu ao menu de aplicativos em uma lista genérica sem expor um
Menu
objeto real, porque a estrutura pode ser implantada em outras plataformas que não possuemMenu
interface do usuário objetos. A adição de informações gerais sobre o menu é bastante fácil, mas permitir ao desenvolvedor do plugin liberdade suficiente para criar o retorno de chamada para quando o menu é clicado estava provando ser um problema. Até que me dei conta de que estava tentando reinventar a chamada do volante e dos menus normais e acionar o retorno de chamada dos eventos!Portanto, a solução, tão simples quanto parece depois que você a percebe, me escapou até agora.
Apenas crie classes separadas para cada um dos métodos atuais, herdadas de uma base, se necessário, e adicione um manipulador de eventos a cada uma.
fonte
Aqui está um exemplo que pode ajudá-lo a entender melhor como passar uma função como parâmetro.
Suponha que você tenha a página pai e deseje abrir uma janela pop-up filho. Na página pai, há uma caixa de texto que deve ser preenchida com base na caixa de texto pop-up filho.
Aqui você precisa criar um delegado.
Parent.cs // declaração dos delegados delegado público void FillName (String FirstName);
Agora crie uma função que preencha sua caixa de texto e a função deve mapear os delegados
Agora, clique no botão, você precisa abrir uma janela pop-up filho.
No construtor ChildPopUp, você precisa criar o parâmetro 'tipo delegado' da página pai //
ChildPopUp.cs
fonte
Se você deseja passar o método como parâmetro, use:
fonte
Aqui está um exemplo sem um parâmetro: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string
com parâmetros: http://www.daniweb.com/forums/thread98148.html#
você basicamente passa uma matriz de objetos junto com o nome do método. você usa os dois com o método Invoke.
params Parâmetros do objeto []
fonte
A segunda classe é o cliente, que usará a classe de armazenamento. Ele possui um método Main que cria uma instância do PersonDB e chama o método Process desse objeto com um método definido na classe Client.
fonte