Basically I'm trying to call a dll by name, instantiate an object, then call a method by name in that dll. I'm getting an "Exception has been thrown by the target of an invocation." during the Method.Invoke. I'm fairly sure my problem is with the typecasting of the arguments of the method. I was wondering if anyone had any input on this exception. Additionally, any suggestions on how to revise my approach are welcome.
public void calldll(string dllName, string typeName, string methodName, string arguments) {
string[] argumentArray = arguments.Split(new char[] { '|' }, StringSplitOptions.None);
Assembly assembly = Assembly.LoadFrom(dllName);
System.Type type = assembly.GetType(typeName);
Object o = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod(methodName);
ParameterInfo[] parameters = method.GetParameters();
object[] methodParameters = new object[parameters.GetLength(0)];
for (int i = 0; i < parameters.Length - 1; i++)
{
var converter = TypeDescriptor.GetConverter(parameters[i].GetType());
methodParameters[i] = converter.ConvertFrom(argumentArray[i]);
}
method.Invoke(o, methodParameters); }
I found two issues with your code:
You are not looping over all parameters. You should remove -1 from the for loop.
When you are creating your converter, you call the GetType() method. This returns the Type of the ParameterInfo object, not the Type of the parameter. Use the property ParameterType instead.
All in all, change the first lines in the for loop to this:
for (int i = 0; i < parameters.Length; i++)
{
var converter = TypeDescriptor.GetConverter(parameters[i].ParameterType);
Once you have done these corrections, I believe your code should run as intended. At least it did for me when I tested a simple void Hello(int x, string y) method.
Related
Help me make clean code. I need to do an action where I can pass a list of fields for validation. In my method I will input string, int, DataTime and display the name of the field where the error is contained. It can be done with many but I want best practices.
I wrote this
public override object Call()
{
DateTime now = DateTime.MinValue;
var validateArguments = ValidateArguments(now);
return validateArguments;
}
private static bool ValidateArguments(params object[] args)
{
for (var i = 0; i < args.Length; i++)
{
if (args[i] == null|| Convert.ToDateTime(args[i])==DateTime.MinValue)
{
StackTrace trace = new StackTrace();
// Get the method that called us
MethodBase info = trace.GetFrame(1).GetMethod();
// Get information on the parameter that is null so we can add its name to the exception
ParameterInfo param = info.GetParameters()[i];
InfoManager.MessageBox("Error in {0}", param.Name);
return false;
}
return true;
}
return false;
}
But this code produces following error:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
How do I fix it or write other clean code?
On this line ParameterInfo param = info.GetParameters()[i]; you are getting the parameters of your method Call() which has no parameters, and then indexing it with [i], this leads to an IndexOutOfRangeException. Perhaps you want to do this ParameterInfo param = info.GetParameters() and check that it is longer than 0 like this if (param.Length > 0). I cannot tell you what to do because I am not sure what you are trying to accomplish. Best of luck!
I am trying to invoke a generic methods that accepts a single params parameter through reflection.
When I picked it to be non generic passing an object[] item seemed to be sufficient but when I reqired to call a generic method it does not work anymore.
var type = typeof (ClassWithGenericMethod);
var method = type.GetMethod("GenericMethod", BindingFlags.Instance | BindingFlags.Public);
var genericMethod = method.MakeGenericMethod(typeof(object));
var result = (bool)genericMethod.Invoke(new ClassWithGenericMethod(), new object[]{"param"});
Assert.IsTrue(result);
The called class:
public class ClassWithGenericMethod
{
public bool GenericMethod<T>(params string[] input)
{
return input.Length == 1;
}
}
The code fails before the assert with the following exception:
Object of type 'System.String' cannot be converted to type
'System.String[]'.
Try repleace new object[]{"param"} with new object[] { new[] { "param" } }.
Here new object[] is the array of parameters, and the first parameter should be a string[], but in your code, you use a string, hence the exception.
When using reflection to call a method that has a params keyword specified, you should just ignore the params keyword. You will need to specify an array of the appropriate type and pass that as the argument.
In your case, instead of passing a single parameter of "param", you need to pass an array of string containing a single item.
The params keyword actually affects how the method caller is compiled. When the compiler sees that the called method specifies "params", it builds the appropriate type of array and passes it. The compiler "magically" turns the following
string result = string.Concat("A","B","C","D");
into basically a compiled version of the following
string[] x = {"A", "B", "C", "D"};
string result = string.Concat(x);
I am loading a dll using reflection and trying to invoke a method that returns a List<customType>. How do I invoke a method and get the return values. I tried this but says entry point not found exception.
MethodInfo[] info= classType.GetMethods();
MethodInfo method = mInfo.FirstOrDefault(c => c.Name == "GetDetails");
object values = method.Invoke(classInstance, new object[] { param1});
values has the exception entry point not found.
Assembly assembly = Assembly.LoadFile(#"assembly location"); // you can change the way you load the assembly
Type type = assembly.GetType("mynamespace.NameOfTheClass");
ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
object classObject = constructor.Invoke(new object[] { });
MethodInfo methodInfo = type.GetMethod("GetDetails");
var returnValue = (List<customType>)methodInfo.Invoke(classObject, new object[] { param1});
A few alterations might be required depending on if your class is static or not and if your constructor takes any parameters.
I can make the type of a delegate at runtime from a list of parameter System.Type, thanks to a answer to a question here.
But how do I do this when one of the parameters is a generic parameter, say it represents something like the following?
delegate t ScanFun<t>();
I want a System.Type which represents a generic delegate so I can call Type.MakeGenericType method with the type for the generic parameter t. However, I can't even find a way to find out what the type of that looks like.
The use is in a code analysis tool. This is the code I have which works with known types:
System.Type[] parms = new Type[f.sig.Parms.list.Length + 1];
specs[0] = f.sig.ReturnType.Type;
for (int i = 0; i < f.sig.Parms.list.Length; i++)
specs[i + 1] = f.sig.Parms.list[i].Type;
for (int i = 0; i < parmTypes_.Length; i++)
{
if (f.sig.Generic.List.Contains(specs[i].Name))
{
/// TODO: Make generic parameter Type here
goto done;
}
parms[i] = f.Parent.findType(specs[i]);
done: ;
}
var dtype = System.Linq.Expressions.Expression.GetDelegateType(parms);
Type openScanFunType = typeof(ScanFun<>);
Type closedScanFunType = openScanFunType.MakeGenericType(new[] { typeof(int) });
Alternatively (and this works better if there are multiple type parameters):
Type openScanFunType = typeof(ScanFun<string>).GetGenericTypeDefinition();
Type cloCsedScanFunType = openScanFunType.MakeGenericType(new[] { typeof(int) });
I'm using the .NET CF 3.5. The type I want to create does not have a default constructor so I want to pass a string to an overloaded constructor. How do I do this?
Code:
Assembly a = Assembly.LoadFrom("my.dll");
Type t = a.GetType("type info here");
// All ok so far, assembly loads and I can get my type
string s = "Pass me to the constructor of Type t";
MyObj o = Activator.CreateInstance(t); // throws MissMethodException
MyObj o = null;
Assembly a = Assembly.LoadFrom("my.dll");
Type t = a.GetType("type info here");
ConstructorInfo ctor = t.GetConstructor(new Type[] { typeof(string) });
if(ctor != null)
o = ctor.Invoke(new object[] { s });
Ok, here's a funky helper method to give you a flexible way to activate a type given an array of parameters:
static object GetInstanceFromParameters(Assembly a, string typeName, params object[] pars)
{
var t = a.GetType(typeName);
var c = t.GetConstructor(pars.Select(p => p.GetType()).ToArray());
if (c == null) return null;
return c.Invoke(pars);
}
And you call it like this:
Foo f = GetInstanceFromParameters(a, "SmartDeviceProject1.Foo", "hello", 17) as Foo;
So you pass the assembly and the name of the type as the first two parameters, and then all the constructor's parameters in order.
See if this works for you (untested):
Type t = a.GetType("type info here");
var ctors = t.GetConstructors();
string s = "Pass me to the ctor of t";
MyObj o = ctors[0].Invoke(new[] { s }) as MyObj;
If the type has more than one constructor then you may have to do some fancy footwork to find the one that accepts your string parameter.
Edit: Just tested the code, and it works.
Edit2: Chris' answer shows the fancy footwork I was talking about! ;-)