Use variable as Type [duplicate] - c#

This question already has answers here:
How do I use reflection to call a generic method?
(8 answers)
Closed 6 years ago.
Is it possible to make such code work?:
private List<Type> Models = new List<Type>()
{
typeof(LineModel), typeof(LineDirectionModel), typeof(BusStopTimeModel), typeof(BusStopNameModel)
};
foreach (Type model in Models) // in code of my method
{
Connection.CreateTable<model>(); // error: 'model' is a variable but is used like a type
}
Thanks in advance

You won't be able to use the variable as a generic type using the conventional syntax (CreateTable<model>). Without knowing what CreateTable does, you have two options:
Instead of making CreateTable a generic method, have it take the type as a parameter:
public static void CreateTable(Type modelType)
{
}
Use Reflection to dynamically invoke the generic method using the desired type:
var methodInfo = typeof (Connection).GetMethod("CreateTable");
foreach (Type model in Models)
{
var genericMethod = methodInfo.MakeGenericMethod(model);
genericMethod.Invoke(null, null); // If the method is static OR
// genericMethod.Invoke(instanceOfConnection, null); if it's not static
}
Note that the reflection way would be slower since the method info won't be resolved until runtime.

You can do it like this,
private List<Type> Models = new List<Type>()
{
typeof(LineModel), typeof(LineDirectionModel), typeof(BusStopTimeModel), typeof(BusStopNameModel)
};
void SomeMethod()
{
MethodInfo genericFunction =Connection.GetType().GetMethod("CreateTable");
foreach (Type model in Models)
{
MethodInfo realFunction = genericFunction.MakeGenericMethod(model);
var ret = realFunction.Invoke(Connection, new object[] { });
}
}

Related

Get the type excluding the standard [duplicate]

This question already has answers here:
How to get the type of T from a member of a generic class or method
(17 answers)
Closed 2 years ago.
I have method like this:
public async Task<IEnumerable<DataResponse>> GetAsync() { ... }
I use reflection and I want to get the type "DataResponse", but I get type "Task<IEnumerable>"
static void Main(string[] args)
{
var assemblies = GetAssemblies();
IEnumerable<Type> controllers =
assemblies.SelectMany(a => a.GetTypes().Where(t => t.IsSubclassOf(typeof(ControllerBase))));
foreach (var controller in controllers)
{
var methods = controller.GetMethods();
foreach (var methodInfo in methods)
{
var returnType = methodInfo.ReturnType;
}
}
}
How do I get types excluding standard types ("task", "IEnumerable", e.t.c)?
Task<IEnumerable> is a generic type whose one generic argument IEnumerable which is in turn a generic type whose generic argument is DataResponse
So methodInfo.ReturnType.GetGenericTypeArguments()[0].GetGenericTypeArguments()[0] would do the trick for this particular method.
Of course this wouldn't solve all cases.
A more generic way
// Pass all types you want to strip here, for example, List<>, IList<>, Task<>, etc.
returnType = StripTypes(returnType, typeof(Task<>), typeof(IEnumerable<>), typeof(List<>));
static Type StripTypes(Type type, params Type[] typesToStrip)
{
if (!type.IsGenericType)
{
return type;
}
var definition = type.GetGenericTypeDefinition();
if (Array.IndexOf(typesToStrip, definition) >= 0)
{
return StripTypes(type.GetGenericArguments()[0], typesToStrip);
}
return type;
}

C# Generics and Reflection - Passing an object to a generic method [duplicate]

This question already has answers here:
How do I use reflection to call a generic method?
(8 answers)
Closed 8 years ago.
I have a method with the following signature:
private string SerialiazeObj<T>(T obj)
{
// Do some work
}
Now, I have another method which accepts an object and calls the SerializeObj method, as shown below:
private void callSerializeObj(object obj)
{
Type objType = obj.GetType();
string s = SerialiazeObj<objType>((objType)obj));
}
The object passed to callSerializeObj can be of any type. Unfortunately, the compiler is giving me this error in the (string s = SerializeObj...) part:
The type or namespace 'objType' could not be found (are you missing an assembly reference).
I don't know if I am calling SerializeObj the correct way. What is the correct way of calling the method with an object which can be of any type?
Use as below -
private void callSerializeObj(object obj)
{
Type objType = obj.GetType();
MethodInfo method = this.GetType().GetMethod("SerialiazeObj", BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo generic = method.MakeGenericMethod(objType );
object Result = generic.Invoke(this, new object[] { obj });
}

Initialize a generic class with the generic type as a variable

internal interface Rule {
}
private class Rule<T> : Rule {
//Properties & Other Stuff
}
void method() {
//For simplicity I used string here. It can be anything when the code is in context
Type _type = typeof(string);
Rule[] _rules;
//This is causing an error because _type could not be found
_rules = new Rule<_type>[] { };
}
Is it even possible to instantiate a class with a generic type that is stored in a variable?
-- EDIT
From my first example I thought I would be able to apply the same concept for calling a method. But it seems that I was wrong. I'm trying to use newtonsoft json library to deserialize a string as a generic type. I found this question that allows you to invoke a method with a generic type. I looked around on how to cast the object to _foo but could only find casting where the type is known. Any idea?
Using Newtonsoft.Json;
void method() {
//For simplicity I used string here. It can be anything when the code is in context
Type _type = typeof(string);
Rule[] _rules;
// ------------------ New Additions ----------------
var _foo = (Rule[])Array.CreateInstance(typeof(Rule<>).MakeGenericType(_type),0);
MethodInfo method = typeof(JsonConvert).GetMethod("DeserializeObject");
MethodInfo generic = method.MakeGenericMethod(_foo.GetType());
//How do you cast this to a type _myType?
_rules = generic.Invoke(this, new[] { "JSON Data" });
}
It's possible, but you have to use reflection:
Type genericTypeDefinition = typeof(Rule<>);
Type genericType = genericTypeDefinition.MakeGenericType(_type);
Rule[] array = (Rule[])Array.CreateInstance(genericType, 0);

Generic method execute with a runtime type [duplicate]

This question already has answers here:
How do I use reflection to call a generic method?
(8 answers)
Closed 8 years ago.
It is strange but the source code
public class Processor<T> where T: class
{
...
private object WorkWithSubtype(IRequester nextRequester, Type type)
{
if (type.GetInterface("IList") != null)
{
var originalType = type.GetGenericArguments()[0];
var list = Activator.CreateInstance(type);
var method = typeof(Processor<>).GetMethod("GetObjects", BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(originalType);
var resList = method.Invoke(this, new object[] { nextRequester });
typeof(List<>).GetMethod("AddRange").MakeGenericMethod(originalType).Invoke(list, new object[] { resList });
return list;
}
}
private IEnumerable<K> GetObjects<K>(IRequester requester) where K: class
{
...
//We can call method WorkWithSubtype in this method sometimes
}
}
And i get "Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.". The exception is throwing at line 'var resList = method.Invoke(this, new object[] { nextRequester });'. Can you help me? Thanks in advance!
You have two generic parameters: one is for the Processor class; the other is for the GetObjects method. In making the generic method, you've supplied a type argument for the method's type parameter, but you haven't supplied a type argument for the class's generic parameter.
Depending on the purpose of the processor class, you could try one of the following solutions:
build the closed generic type with a type argument
use typeof(Processor<T>) rather than using reflection to build the closed generic type
remove the type parameter from the class
remove the type parameter from the method
I think the second is most likely to be what you're looking for:
var method = typeof(Processor<T>)
.GetMethod("GetObjects", BindingFlags.NonPublic | BindingFlags.Instance)
.MakeGenericMethod(originalType);
Additionally, AddRange is not a generic method; rather, List<> is a generic type, so:
typeof(List<>)
.MakeGenericType(originalType)
.GetMethod("AddRange")
.Invoke(list, new object[] { resList });
You need to use MakeGenericType like so:
var method = typeof(Processor<>).MakeGenericType(typeof(T)).GetMethod("GetObjects", BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(originalType);
similarly when you invoke the AddRange method.
The problem is that List<string>.AddRange is a different method than List<int>.AddRange and MakeGenericType applies the type parameter to the class. Calling MakeGenericMethod is still required for GetObjects since it has a different generic type parameter (K) than the containing class (T).

How to get MethodInfo from a method symbol [duplicate]

This question already has answers here:
get methodinfo from a method reference C#
(7 answers)
Closed 9 years ago.
Is it possible to get a MethodInfo object from a method symbol?
So in the same vein as:
typeof(SomeClassSymbol) // this gets you a Type object
Here is what I want to do:
public class Meatwad
{
MethodInfo method;
public Meatwad()
{
method = ReflectionThingy.GetMethodInfo(SomeMethod);
}
public void SomeMethod() { }
}
How could I implement ReflectionThingy.GetMethodInfo? Given this is even possible at all, what about overloaded methods?
Delegates contain the MethodInfo you want in their Method property. So your helper method could be as simple as:
MethodInfo GetMethodInfo(Delegate d)
{
return d.Method;
}
You cannot convert directly from a method group to Delegate. But you can use a cast for that. E.g.:
GetMethodInfo((Action)Console.WriteLine)
Be aware that this won't work if you try to mix it with something like usr's solution. For example
GetMethodInfo((Action)(() => Console.WriteLine()))
will return the MethodInfo for the generated anonymous method, not for Console.WriteLine().
This is not possible in C# directly. But you can build this yourself:
static MemberInfo MemberInfoCore(Expression body, ParameterExpression param)
{
if (body.NodeType == ExpressionType.MemberAccess)
{
var bodyMemberAccess = (MemberExpression)body;
return bodyMemberAccess.Member;
}
else if (body.NodeType == ExpressionType.Call)
{
var bodyMemberAccess = (MethodCallExpression)body;
return bodyMemberAccess.Method;
}
else throw new NotSupportedException();
}
public static MemberInfo MemberInfo<T1>(Expression<Func<T1>> memberSelectionExpression)
{
if (memberSelectionExpression == null) throw new ArgumentNullException("memberSelectionExpression");
return MemberInfoCore(memberSelectionExpression.Body, null/*param*/);
}
And use it like this:
var methName = MemberInfo(() => SomeMethod()).MethodName;
That will provide you compile-time safety. Performance will not be good though.

Categories