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);
Related
I have an XML file with classes name like this:
<ActiveMonitorsList>
<MonitorName>CertificatesMonitor</MonitorName>
<MonitorName>ServicesMonitor</MonitorName>
<MonitorName>LogsMonitor</MonitorName>
<MonitorName>DBMonitor</MonitorName>
</ActiveMonitorsList>
Each of this classes containts a method: bool SingleCheck();
I would like to execute this bool SingleCheck() method for each class that is in this XML file.
What is the best way to do this?
This is what I have so far - it doesn't work:
foreach (string monitorName in monitorsList)
{
Type thisType = GetType();
MethodInfo singleMonitorMethod = thisType.GetMethod("{monitorName}.SingleCheck");
bool methodResult = singleMonitorMethod.Invoke(...);
}
In place of (...) - don't know what to put here, but I want to get
the result of the method (it's always bool).
All of those methods I want to pass as paramters are static.
I guess delegates, Actions or Func<> have to go in here...
Thank You very much in advance!
Edit: Each name in XML points to a separate class. Each class have the same named method: public static bool SingleCheck().
What I want to do is:
get all the monitors names (classes names will be the same)
invoke a method (it has the same name in each class) inside EVERY
class present on that list.
EDIT - PROBLEM SOLVED:
When I first created my project, I included separate folder for all monitors. Then I changed my mind, deleted this folder and added manually SAME FILES to my solution. In this way - those files still had "using <namespace>.Monitors"...
And that's why I couldn't list those classes and the Types were still nulls...
Thanks for all suggestions ! ;)
I would suggest to take this overload of the method Invoke It wants an object(calling instance) and a set of input parameters for the method from you.
Since it is a static method, you can calmly pass null as the first parameter and because you method does not have any parameters you again can calmly pass null as the second value. Don't forget to cast object to the corresponding return type. In your case bool.
bool methodResult = (bool)singleMonitorMethod.Invoke(null, null);
To get the correct Type you actually need to know the namespace! So this would look like this:
foreach (string monitorName in monitorsList)
{
string typeName = $"{yourNameSpace}.{monitorName}";
Type thisType = Type.GetType(typeName);
MethodInfo singleMonitorMethod = thisType.GetMethod("SingleCheck");
bool methodResult = (bool)singleMonitorMethod.Invoke(null, null);
}
If the loop is in the same namespace this should also work:
Type thisType = Type.GetType($"{GetType().Namespace}.{monitorName}");
thisType.GetMethod("{monitorName}.SingleCheck") won't work because of two reasons. 1) You forgot the string interpolation $-sign and thus are searching for a method called "{monitorName}.SingleCheck" which obviously can't exist with such a name. 2) Instead of thisType you need to provide the type containing the method.
Invoke needs to be called with the instance as first parameter - null for static methods - and an object array for the method parameters.
Assuming that your monitor classes are in the same assembly like your current type you would need to do the following:
foreach (string monitorName in monitorsList)
{
Type monitorType = GetType().Assembly.GetExportedTypes().Single(x => x.Name == monitorName);
MethodInfo singleMonitorMethod = monitorType.GetMethod("SingleCheck");
bool methodResult = (bool)singleMonitorMethod.Invoke(null, Array.Empty<object>());
}
I prefer Array.Empty over new object[0] or new object[] { } because it doesn't create a new object every time.
Edited: Changed the type discovery according to Mong Zhu's comment that GetType(monitorName) does need the fully-qualified name.
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 am trying to get the MethodInfo from a method TableExists<T> so I can call it with a type.
The method is declared inside OrmLiteSchemaApi class. There are 2 overloads:
public static bool TableExists<T>(this IDbConnection dbConn)
{
// code omitted
}
public static bool TableExists(this IDbConnection dbConn, string tableName, string schema = null)
{
// code omitted
}
I am trying to get the MethodInfo like this:
var tableMethod = typeof(OrmLiteSchemaApi).GetMethod("TableExists");
But it generates exception:
System.Reflection.AmbiguousMatchException: 'Ambiguous match found.'
I could only find an old question related to this that suggested to pass an empty object array as parameter but this doesn't seem to work for .net core.
I guess I need to specify the specific overload but I am not sure exactly how.
How do I get the MethodInfo?
You can use GetMethods (plural!) to get an array of all matching methods, and then look for the one which has IsGenericMethod:
var tm = typeof(OrmLiteSchemaApi)
.GetMethods()
.Where(x => x.Name == "TableExists")
.FirstOrDefault(x => x.IsGenericMethod);
I recommend this over using parameter specifiers, since it'll give you an object you can step through at debug time if there are ever any problems.
Passing an empty object array would only work if you're looking for a function with no parameters. Instead, you need to use a different overload of GetMethod that specifies the types of parameters as a type array. That way you can tell it which reference to get by specifying which types of parameters it should look for.
void A(object o)
{
...
Assembly a = Assembly.LoadFile(...);
Type t = a.GetType(#"namespace.className");
MethodInfo mi = t.GetMethod(#"MethodName");
mi.Invoke(instace, new Object[] {o});
....
}
the method I need to invoke accept another type, I need to cast the object to that type, but, the type is known only at run time, so can I convert/cast object to another type known only at run time ? I can change only method A.
thank you.
The Reflection APIs only deal with object references. Casting a reference is an operation on that reference. It does not affect the object in any way.
For that reason it is not necessary to cast anything here. Just pass o to Invoke like you are already doing. The Reflection API validates the type of o and passes it to the method you want to call.
The MethodInfo.Invoke(object instance, object[] arguments) is dynamic invoke. That means, the casting is made automatically. If is thrown InvalidCastException, then you pass the wrong argument or the exception is thrown from inner code and is not caused by object passed to arguments.
This is the code I used when I had several similar messages coming need, that needed different handling. Ordertype was a Type instance of a custom order object.
var _ot = Activator.CreateInstance(ordertype);
var _otconvert = ordertype.GetMethod("ConvertRequestPayload");
object[] _params = new object[] {message};
var objectf = _otconvert.Invoke(_ot, _params);
var _as = Activator.CreateInstance(servicetype);
var _method = servicetype.GetMethod("StartProcess");
var rMessage = _method.Invoke(_as, new object[] {objectf});
Basically Activator is what you need. it allows you create objects of required type at runtime.
I changed {object 0}to {dynamic 0} and it worked.
Let's say I have such a generic class
public class XClass<T, U>
{
public void MethodA<V>(){}
}
How could I get the type of
XClass<int,>
not hard-coded, not limiting to MakeGenericType method as below.
------ detailed elaboration below using MakeGenericType ------
I can get the type of the unbound and open class "XClass<,>" and its open method:
var type = typeof(XClass<,>);
Console.WriteLine(String.Format("Type ZClass<,>: \t generic? {0} \t open? {1}"
, type.IsGenericType, type.IsGenericTypeDefinition));
var method = type.GetMethod("MethodA");
Console.WriteLine(String.Format("Method MethodA<>: \t generic? {0} \t open? {1}"
, method.IsGenericMethod, method.IsGenericMethodDefinition));
Also, I can get the type of full closed class
XClass <int, char>
and its close method:
var type = typeof(XClass<,>);
var method = type.GetMethod("MethodA");
var fullType = method.DeclaringType.MakeGenericType(new[]{typeof(int), typeof(char)});
Console.WriteLine(String.Format("Type ZClass<int,char>: \t generic? {0} \t open? {1}"
, fullType.IsGenericType, fullType.IsGenericTypeDefinition));
var fullTypeOpenMethod = fullType.GetMethod("MethodA");
var fullMethod = fullTypeOpenMethod.MakeGenericMethod(typeof(string));
Console.WriteLine(String.Format("Method MethodA<String>:\t generic? {0} \t open? {1}"
, fullMethod.IsGenericMethod, fullMethod.IsGenericMethodDefinition));
Now, How can I get the type of bound but open class
XClass<int, >
and its method?
var type = typeof(XClass<,>);
var method = type.GetMethod("MethodA");
Type [] types = new Type[2];
types[0] = typeof(int);
types[1] = null; // what shall i put here?
var halffullType = method.DeclaringType.MakeGenericType(types);
If I put types[1] as null, an ArgumentNullException exception will throw "Value cannot be null".
What should I do?
What you are proposing to do is impossible and also will not really help you.
Impossible because...
The documentation states (emphasis mine) that
Types constructed with MakeGenericType can be open, that is, some of
their type arguments can be type parameters of enclosing generic
methods or types.
This means that you cannot make a Type object representing XClass<int,>. What you can do is:
class Outer<TOuter>
{
class XClass<T, U> {}
}
In this situation, you can make a Type object representing Outer<TOuter>.XClass<int, TOuter>. But there needs to be an enclosing generic class.
Not useful because...
The documentation also states (referring to a similar example to the above) that:
A constructed type such as Base is useful when emitting code,
but you cannot call the MakeGenericType method on this type because it
is not a generic type definition. To create a closed constructed type
that can be instantiated, first call the GetGenericTypeDefinition
method to get a Type object representing the generic type definition
and then call MakeGenericType with the desired type arguments.
Which means that if you have
Type myType = ... // represents Outer<TOuter>.XClass<int, TOuter>
Then to get a Type for XClass<int, string> you would first need to call myType.GetGenericTypeDefinition() (thus losing the int information) and then call MakeGenericType to put it back in (along with the string type parameter). So it's like one step back and two steps forward.
Alternatives
You might want to consider storing the type parameter types for XClass in a separate data structure (e.g. a Type[]) for as long as not all type parameters are known to you, and then create the closed generic type in one go after you have collected all of them.
You can also package all this into a small helper class for convenience:
class GenericTypeDescription
{
private readonly Type openGenericType;
private readonly Type[] typeParameters;
public GenericTypeDescription(Type openGenericType)
{
// add checks for openGenericType actually being what it says here
this.openGenericType = openGenericType;
this.typeParameters = new Type[openGenericType.GetGenericArguments().Length];
}
public void SetTypeParameter(int index, Type type) {
// add error handling to taste
this.typeParameters[index] = type;
}
public Type ConstructGenericType() {
// add error handling to taste
return this.openGenericType.MakeGenericType(this.typeParameters);
}
}
No, this isn't possible.
See my similar question: Does .Net support curried generics?
This is possible, when you feed MakeGenericType with its own generic arguments.
var type = typeof(XClass<,>);
var method = type.GetMethod("MethodA");
Type[] types = new Type[2];
types[0] = typeof(int);
types[1] = type.GetGenericArguments()[1]; // Use the open parameter type
var openConstructedType = type.MakeGenericType(types);
This will populate openConstructedType with a Type of XClass<int,U>.
Note that the type will have ContainsGenericParameters, so it won't be constructable, and there's no way to populate the open parameters.
I don't think that this is possible without inheriting from the class.
What you seem to be trying is to basically do this via reflection:
typeof(XClass<int,>)
This would be half-closed... and only possible by inheritance AFAIK:
class XClassInt<U>: XClass<int, U> {}
This second code allows you to get typeof(XClassInt<>).BaseType which is kind of what you want. However, in that case the second type argument for XClass<,> is not null but actually U (the type argument coming from XClassInt<>).
See also this MSDN page.
Edit: Here's my testbed for this:
public class C1<A,B> {}
public class C2<B>: C1<int, B> {}
[...]
Type baseType = typeof(C2<>).BaseType;
WL(baseType);
WL(baseType.GetGenericArguments()[0]);
Type arg1 = baseType.GetGenericArguments()[1];
WL(arg1);
WL(arg1.DeclaringType);
WL(arg1.GenericParameterPosition);
WL(arg1.IsGenericParameter);
Running this yields:
C1`2[System.Int32,B]
System.Int32
B
C2`1[B]
0
True
However, as I said, I believe this is only possible because the base type is closed with the generic type argument of the open generic type C2.