Como modificar um tipo de valor em caixa dentro de um método
-
08-07-2019 - |
Pergunta
Estou tring para construir uma biblioteca para simplificando chamadas de ligação tardia em C #, e eu estou começando problemas tring com parameteres referência. Eu tenho o seguinte método para adicionar um parâmetro usado em uma chamada de método
public IInvoker AddParameter(ref object value)
{
//List<object> _parameters = new List<object>();
_parameters.Add(value);
//List<bool> _isRef = new List<bool>();
_isRef.Add(true);
return this;
}
E isso não funciona com tipos de valor, porque eles são encaixotados como um objeto, portanto, eles não são modificados. Por exemplo:
int param1 = 2;
object paramObj = param1;
//MulFiveRef method multiplies the integer passed as a reference parameter by 5:
//void MulFiveRef(ref int value) { value *= 5; }
fi.Method("MulFiveRef").AddParameter(ref paramObj);
Isso não funciona. A chamada ligação tardia for bem sucedida, ea lista interna que detém os parameteres (_parameters) não são modificados, mas não o valor fora da chamada.
Alguém sabe uma maneira simples de superar essa limitação? A assinatura addParameter não podem ser modificados, como acontece com as chamadas ligação tardia, não é possível saber com antecedência o tipo de parâmetros (e de qualquer forma você inserir todos os parâmetros para uma chamada dentro de uma matriz de objeto antes de fazer a chamada)
Agradecemos antecipadamente.
Solução
Se o valor está mudando dentro do método , você precisará declarar uma variável temporário (object
) para passar (ref
) para o método, e unbox-lo sozinho depois:
int i = 3;
//...
object obj = i;
Foo(ref obj);
i = (int)obj;
Note que isso não irá permitir que você atualizar o valor após o evento. Algo como um evento ou de retorno de chamada pode ser uma forma alternativa de passar alterações de volta para o chamador.
Note-se também que o C # 4.0 tem alguns truques para ajudar com esta única no contexto das chamadas COM (onde ref object
é tão comum [mais claro dynamic
para a ligação tardia, como observa Jon]).
Outras dicas
Seu método não está mudando value
de qualquer maneira - por que você está passando-o por referência? Pode fazer sentido, mas não é muito claro para mim. Note que o código de exemplo que você forneceu não compilar de qualquer maneira, como argumentos ref
tem que ser exatamente do mesmo tipo que o parâmetro.
(Além disso, você está ciente de que o C # 4.0 e .NET 4.0 terá suporte embutido para a ligação tardia? As chances são de que a versão integrada de línguas vai ser mais fácil de usar do que uma biblioteca de apenas um. Tem certeza vale a pena passar um tempo na biblioteca neste momento no tempo?)
EDIT: O código que você forneceu realmente não irá compilar. Você não consegue boxe para parâmetros ref
, precisamente porque os tipos de argumento e parâmetro tem que ser exatamente o mesmo. Aqui está um código de exemplo para provar isso:
public class Test
{
static void Main()
{
int i;
Foo(ref i); // Won't compile - error CS1502/1503
}
static void Foo(ref object x)
{
}
}
Se o seu código atual é compilação, então não é o código apresentado na pergunta. Talvez você tem uma outra sobrecarga para AddParameter
que aceita ref int
?
Ok, graças a correções Jon Skeet e código Mark Gravell, eu vim acima com esta interface:
//This will be created with a factory
IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());
int param1 = 2;
object paramObj = param1;
invoker.AddParameter(ref paramObj).Invoke("MulFiveRef");
param1 = (int)invoker.Parameters[0];
Não é exatamente como eu imaginei, mas é a maneira mais simples e legível que minha interface anterior:
IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());
int refValue = 10;
object[] args = Args.Build(refValue);
invoker.Call("MulFiveRef", Args.ByRefIndexs(0), args);
refValue = (int)args[0];
Muito obrigado pela vossa ajuda as pessoas:)