I have a function that calls other functions dynamically via name. I need to pass a hashtable to the function being called. I have the code working in VB.Net but while trying to convert it to C# I am running into a error when I try to pass the hashtable as a parameter. Can someone explain what is happening and how I can resolve it?
This is the working VB.Net code:
Dim objTF As New ThreadFunctions
Dim objResults As Object = CallByName(objTF, htParameters.Item("strMethodName"), CallType.Get, htParameters)
Here is the C# code:
ThreadFunctions objTF = new ThreadFunctions();
Type objType = objTF.GetType();
MethodInfo miMethod = objType.GetMethod(htParameters["strMethodName"].ToString());
object objResults = miMethod.Invoke(objTF, htParameters); //This line has the issue
Error 1 The best overloaded method match for 'System.Reflection.MethodBase.Invoke(object, object[])' has some invalid arguments
Try
object objResults = miMethod.Invoke(objTF, (object)htParameters);
As the params second argument threats the hashtable wrong.
Related
I am working on being able to dynamically invoke an instantiation of a class dynamically at run time.
I have spent the better part of this morning searching Google for an answer but I am pretty green in this world so I am sure the answers make sense, but they do not to me.
public class MSD : IGBRule
{
public MSD(GoverningBodyRulesGet_Result GBRule, int UserID)
{}
The line error and the error are both below
object v = Activator.CreateInstance(Type.GetType("RulesEngine.Rules.MSD, RulesEngine.Rules"), UserID, GBRules);
System.MissingMethodException: 'Constructor on type 'RulesEngine.Rules.MSD' not found.'
If you want to create an object and pass arguments to the constructor, you will have to provide the arguments in the correct order, matching the order you have specified in your constructor. So in your case, you want to pass the rule before the user id:
var type = Type.GetType("RulesEngine.Rules.MSD, RulesEngine.Rules");
object v = Activator.CreateInstance(type, GBRules, UserID);
If you pass the constructor arguments directly to the CreateInstance method, you will have to be careful with common types as it is possible that you are accidentally selecting a different overload that doesn’t call the correct constructor. You can avoid that by passing an object array with the arguments you want to pass:
var type = Type.GetType("RulesEngine.Rules.MSD, RulesEngine.Rules");
object[] args = new object[] { GBRules, UserID };
object v = Activator.CreateInstance(type, args);
I was looking around here for the answer to this question, and I found a lot of similar questions
Passing just a type as a parameter in C#
X is a variable but used like a type when trying to cast
how to adjust "is a type but is used like a variable"?
How to pass an Object type to Type parameter in C#
Generic List<T> as parameter on method, Initializing a Generic variable from a C# Type Variable
How do I use reflection to call a generic method?
Reflection To Execute Class With Generic Type
but I wasn't able to use any of them to solve my particular issue.
Basically, I have a class (that I don't want to modify) that is activated in a form like so:
var myEvent = new EventListener<KeyboardEvent/*or other type of event*/>((e) => {
///do stuff with event "e"
});
I want to make a function that makes a new event listener "dynamically", meaning based on a particular variable for the "event type" (forget about the function body for now, just assume they all have the same function body), like:
void makeEvent(Type eventType) {
var myEvent = new EventListener<eventType>((e) => {
///do stuff with event "e"
});
}
as many of you will know, as did those people who posted the above questions, that simple doing that will give a "variable used like a type" error, and it won't work, and many of them suggested using "reflection" to get around this, like (from Reflection To Execute Class With Generic Type):
ar instance = Activator.CreateInstance(implementation);
var results = this.GetType()
.GetMethod("CheckForMessages", BindingFlags.NonPublic | BindingFlags.Instance)
.MakeGenericMethod(interfaceUsesType)
.Invoke(this, null) as object[];
if(results.Count() > 0)
instance.GetType()
.GetMethod("DoThis")
.Invoke(instance, new object[] {results});
or (from Initializing a Generic variable from a C# Type Variable):
Animal a = MyFavoriteAnimal();
var contextType = typeof(EsbRepository<>).MakeGenericType(a.GetType());
dynamic context = Activator.CreateInstance(contextType);
context.DoAnimalStuff();
So these answers theoretically make a class definition, but in my case I need to do 2 things, #1: make the actual class of the EventListener, and #2 actually give the class a body (via the lambda expression above), so how can I do that with Activator.CreateInstance ? Or Is there any other way?
Basically I can't use a lambda in the object[], because its not an object, and if I use an Action of some kind that is an object, then I would need to pass in a generic type, and I'm back to where I started, for example I could theoretically do:
var myType = typeof(EventListener<>).MakeGenericType(eventType);
Activator.CreateInstance(myType, new object[] {
new Action<KeyboardEvent>(e => {})
});
which would compile, but then I'm back to where I started in the first place, because "KeyboardEvent" is itself what I need to change, and if I do:
Action<myDynamicTypeVariable>(e=>{})
I get the same "variable is used as type" error...
Isn't there just some kind of way to actually use a variable as a type?
Or is there a way to set the body of a function after the class instance has been formed?
Or how can I pass in a generic function as one of the object[] arguments without having to specify the type of the function and without using lambdas?
I've found lots of info on passing parameters to methods and found that having the method use params Object[] args to be a great (and sometimes only) way to do this.
i.e. sample method:
public void someMethod(params object[] args)
{
//do something
}
But when passing the parameter object like this to a Com Method, it doesn't work:
object[] passParameters = new object[2];
passParameters[0] = "test1";
passParameters[1] = "test2";
//Calling method compiled with with CodeDom
MethodInfo method = classObject.GetType().GetMethod("someMethod");
object dynamicOutput = method.Invoke(classObject, passParameters);
For it to work, I have found that I need to pass the parameter object as a new Object:
object dynamicOutput = method.Invoke(classObject,(new object[] { passParameters });
Can anyone please explain to me why I need to do this and what the reasoning is behind it? Thanks.
They don't. You can just use them as
someMethod("test1", "test2", ... )
BUT. If you're creating an array beforehand, it has to be passed differently, as you encountered
I've come to realise that the original passParameters object in the example contains two elements, as we know:
passParameters[0] = "test1";
passParameters[1] = "test2";
However, when the array is passed to the Com method, it requires being passed as so:
new object[] { passParameters })
My understanding of this is, that it creates a new object array which has put the existing 'passParameters' array into its first element [0] (effectively creating a new 2d array):
passParameters[0][0] = "test1";
passParameters[0][1] = "test2";
The method MethodInfo class in my question, required a single object passed to the Invoke method, which meant that the original 'passParameters' object with its two elements had too many arguments. By passing it inside a new object, this passes all of the elements as a single object, but containing an array of those parameters.
I am learning C# and have a very basic background in Python where I was familiar with the type() function where the data type of a variable can be returned via:
type(myVariable)
Is there a C# equivalent to this function?
I am asking in the context of wanting to use such a function on a C# variable that has been created using var eg:
var myNewVariable = "Hello!"
I am using explicit data types in general eg:
string myNewString = "Hello!"
But I am just wondering what data type a variable created using var defaults to and thought something similar to type() would be a good way to check out what was happening 'under the hood` so to speak.
You can try using GetType() method:
Type myType = myVariable.GetType();
For instance
String typeName = "My String".GetType().Name; // <- "String"
You have couple of options here
typeof. typeof takes a type name (which you specify at compile time).
GetType gets the runtime type of an instance.
Example
B a = new B();
a.GetType() == typeof(B)
Note: a is an instance of an object B. Whereas B is a type.
How could I go about calling a method on a static class given the class name and the method name, please?
For example:
Given System.Environment and GetFolderPath, I'd like to use Reflection to call Environment.GetFolderPath().
Just
Type.GetType(typeName).GetMethod(methodName).Invoke(null, arguments);
where typeName is the name of the type as a string, methodName is the name of the method as a string, and arguments is an array of objects containing the arguments to call the method with.
First you need to get the Type (by iterating on the assembly using reflection)
see this link for details: http://msdn.microsoft.com/en-us/library/system.reflection.propertyinfo.aspx
or use
Assembly.GetType
once you have the type in hand you can iterate over members using reflection or
MethodInfo method = typeof(MyClass).GetMethod("MyMethod");
then you can use MethodInfo.Invoke and pass arguments to invoke the method when you want to invoke it.
System.Reflection.Assembly info = typeof(System.Environment).Assembly;
Type t = info.GetType("System.Environment");
MethodInfo m = t.GetMethod("GetFolderPath");
object result = m.Invoke(null, arguments);
What you are doing here is reflecting on the type named Environment and using the GetPropery and GetGetMethod methods to get the get method of the Environment.CurrentDirectory property like so;
var getMethod = typeof(Environment).GetProperty("CurentDirectory", BindingFlags.Public | BindingFlags.Static).GetGetMethod();
var currentDirectory = (string)getMethod.Invoke(null, null);
Calling the get method of a property returns it's value and is equivilent to;
var value = Environment.CurrentDirectory;
Here is a basic outline of what you would do:
Scan all the objects in the current AppDomain - find the one that matches what you know the class name to be
Get the static method with the name you know on that object
Dynamically invoke it.
Edit: This will work if you do not know the namespace of the static class. Otherwise use Daniel Brückner's solution as its much simpler.