MethodInfo.Invoke, parameter values are not updated.

J

JP Wrye

Hello All,

I'm working on a utility that will let me orchestrate when methods are
invoked. As I Invoke each method I'm passing an object whose values I want
to change with the implementation of each method. The methods invoke in the
correct order, but the parameters that are passed aren't updated. I changed
the parameter type to be passed as ref, but now the method signature doesn't
match, and I still don't know if changes I make to the parameter will be
returned by ref.

Is this a limitation of using MethodInfo.Invoke?

Thanks,
JP
 
I

Imran Koradia

Could you post the code? That might help figuring out what's going on..

Imran.
 
J

JP Wrye

Sure,

//The Method to be invoked.
public class TestMethods
{
public TestMethods()
{}

public string TestInvoke(string parameter1)
{
parameter1 = "Changed parameter1 value";
return parameter1;
}
}

//The class to use InvocationHandler.
public class InvokeMethods
{

public void Invoke()
{
TestMethods _testMethods = new TestMethods()
InvocationHandler _invocationHandler = new
InvocationHandler(_testMethods,
"TestInvoke",
new object[] {"parameter1 value"})

}

}

public class InvocationHandler
{
private object _handler;
private string _methodName;
private object[] _parameters;

#region Constructor
public InvocationHandler(object handler, string methodName, Array
parameters)
{
_handler = handler;
_methodName = methodName;
_parameters = (object[])parameters;
}
#endregion

#region Method
public void Invoke()
{
Type[] _parameterTypes = new Type[_parameters.Length];

for(int _index = 0; _index < _parameters.Length; _index++)
{_parameterTypes[_index] = _parameters[_index].GetType();}

MethodInfo _method = _handler.GetType().GetMethod(_methodName,
_parameterTypes);

if (_method == null)
{throw new
ConfigurationException(Resources.ResourceManager[Resources.MessageKey.Method
NameNotFound,
_methodName, _handler]);}

_result = _method.Invoke(_handler, _parameters);
}
#endregion
}


I get the "_result" of the method("Changed parameter1 value"), but if I
index into the "_parameter" array "_parameter[0]", the value isn't updated.
It's still "parameter1 value".

Thanks,
JP
 
M

Mattias Sjögren

I get the "_result" of the method("Changed parameter1 value"), but if I
index into the "_parameter" array "_parameter[0]", the value isn't updated.
It's still "parameter1 value".

That's because you're not changing the object that's passed in as an
argument, you're just reassigning the parameter which leaves the
callee reference unaffected since the parameter is passed by value.

The same happens if you make an early bound call

string s = "parameter1 value";
test.TestInvoke(s);
// s unchanged here


Making it a ref parameter should solve it. But then you have to change
the type lookup to something like

Type byval = _parameters[_index].GetType();
_parameterTypes[_index] =
byval.Assembly.GetType(byval.FullyQualifiedName + "&");

or if you're lucky enough to use Whidbey

_parameterTypes[_index] =
_parameters[_index].GetType().MakeByRefType();



Mattias
 
I

Imran Koradia

JP,

strings - although reference types - behave a little differently. If you
call the method directly also, you'll notice that the parameter you pass in
does not change.

TestMethods tm = new TestMethods();
string param = "parameter1 value";
tm.TestInvoke(param);
Console.WriteLine(param);

This will still print "parameter1 value" to the console. You'll have to
define the parameter as a ref parameter and make the call accordingly as
well.

public string TestInvoke(ref string parameter1)
{
parameter1 = "Changed parameter1 value";
return parameter1;
}

TestMethods tm = new TestMethods();
string param = "parameter1 value";
tm.TestInvoke(ref param);
Console.WriteLine(param);

This will now print "Changed parameter1 value" to the console. So, you'll
have to change your TestInvoke method to take in a ref string parameter.

Now regarding MethodInfo.Invoke, can you not use the GetMethod that just
takes in the method name? Here's how:

public void Invoke()
{
// Type[] _parameterTypes = new Type[_parameters.Length];

// for(int _index = 0; _index < _parameters.Length; _index++)
// {_parameterTypes[_index] = _parameters[_index].GetType();}

System.Reflection.MethodInfo _method =
_handler.GetType().GetMethod(_methodName);

if (_method == null)
{
//throw new
ConfigurationException(Resources.ResourceManager[Resources.MessageKey.Method
NameNotFound, _methodName, _handler]);
}
string _result = (string)_method.Invoke(_handler, _parameters);
Console.WriteLine(_parameters.GetValue(0).ToString());
}

If you need to use the parameters anyway, you will need to indicate that the
parameter is a ref parameter when getting the Type of the parameter. Here's
how:

public void Invoke()
{
Type[] _parameterTypes = new Type[_parameters.Length];

for(int _index = 0; _index < _parameters.Length; _index++)
{_parameterTypes[_index] =
Type.GetType(_parameters[_index].GetType().FullName + "&");}

System.Reflection.MethodInfo _method =
_handler.GetType().GetMethod(_methodName, _parameterTypes);

if (_method == null)
{
//throw new
ConfigurationException(Resources.ResourceManager[Resources.MessageKey.Method
NameNotFound, _methodName, _handler]);
}
string _result = (string)_method.Invoke(_handler, _parameters);
Console.WriteLine(_parameters.GetValue(0).ToString());
}


hope that helps..
Imran.


JP Wrye said:
Sure,

//The Method to be invoked.
public class TestMethods
{
public TestMethods()
{}

public string TestInvoke(string parameter1)
{
parameter1 = "Changed parameter1 value";
return parameter1;
}
}

//The class to use InvocationHandler.
public class InvokeMethods
{

public void Invoke()
{
TestMethods _testMethods = new TestMethods()
InvocationHandler _invocationHandler = new
InvocationHandler(_testMethods,
"TestInvoke",
new object[] {"parameter1 value"})

}

}

public class InvocationHandler
{
private object _handler;
private string _methodName;
private object[] _parameters;

#region Constructor
public InvocationHandler(object handler, string methodName, Array
parameters)
{
_handler = handler;
_methodName = methodName;
_parameters = (object[])parameters;
}
#endregion

#region Method
public void Invoke()
{
Type[] _parameterTypes = new Type[_parameters.Length];

for(int _index = 0; _index < _parameters.Length; _index++)
{_parameterTypes[_index] = _parameters[_index].GetType();}

MethodInfo _method = _handler.GetType().GetMethod(_methodName,
_parameterTypes);

if (_method == null)
{throw new
ConfigurationException(Resources.ResourceManager[Resources.MessageKey.Method
NameNotFound,
_methodName, _handler]);}

_result = _method.Invoke(_handler, _parameters);
}
#endregion
}


I get the "_result" of the method("Changed parameter1 value"), but if I
index into the "_parameter" array "_parameter[0]", the value isn't updated.
It's still "parameter1 value".

Thanks,
JP


Imran Koradia said:
Could you post the code? That might help figuring out what's going on..

Imran.

in
the
 
J

Jon Skeet [C# MVP]

Imran Koradia said:
strings - although reference types - behave a little differently.

No they don't. Strings behave just like all other reference types -
changing the value of a reference type variable doesn't change the
value of any other reference type variable which previously had the
same value. That's true of strings and all other reference types.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top