I have a generic as follows.
public class PaginatedList<T> : List<T>
{...}
I simply want to invoke ToList() method on that object at runtime using reflection.
Can someone please help.
I have come so only far.
MethodInfo toListMethod = typeof(Enumerable).GetMethod("ToList");
var constructedToList = toListMethod.MakeGenericMethod(TypeObjectOfT);
constructedToList.Invoke(paginatedListObject, null);
I get exception at the last line with message, Parameter count mismatch. I feel that the first two steps are ok, as I have checked the toListMethod.ToString() and constructedToList.ToString(). And they have given me the following output, which I feel is correct.
System.Collections.Generic.List`1[TSource] ToList[TSource](System.Collections.Generic.IEnumerable`1[TSource])
System.Collections.Generic.List`1[AvbhHis.BL.Entities.PatientCategory] ToList[PatientCategory](System.Collections.Generic.IEnumerable`1[AvbhHis.BL.Entities.PatientCategory])
Questions:
1. Am I right so far?
What should be the parameter to MakeGenericMethod() method. In my case it is the Type of intance of the object of Type T at runtime.
There seems to be some problem with the Invoke method call. Is passing null correct as second parameter? The first parameter should be an object of the type PaginatedList right?
My energy is out, so kindly help.
The first parameter [to Invoke] should be an object of the type PaginatedList right?
ToList is a static method on Enumerable that takes an IEnumerable<T> as it's only parameter:
public static List<TSource> ToList<TSource>(
this IEnumerable<TSource> source
)
Invoke takes the instance as the first parameter and the method parameters after that. For a static method you use null for the "instance" parameter.
So the proper syntax would be
object o = constructedToList.Invoke(null, new object[] {paginatedListObject});
o will then be an object of type List<T> (but you don't know kniw what T is at compile time, so you can't cast it).
List<T> has a constructor that takes an IEnumerable<T> (Which gets called in ToList) so you can simplyfy this task by writing the following:
var resul = Activator.CreateInstance(typeof(List<>).MakeGenericType(TypeObjectOfT), paginatedListObject);
Related
I need to execute some chained methods using reflection.
What I´m trying to get is an IQueryable of a Entity Core DBContext Set of an unknown compile type:
var type = typeof(x);
this.DBContext.Set(type).AsQueryable();
Obviously, that code does not compile because Set is a generic Method where the type must be defined in compile time:
this.DBContext.Set<TUnknownType>().AsQueryable();
To solve that, I tried to execute the methods using reflection:
MethodInfo dbSetMethod = typeof(DbContext).GetMethod(nameof(DbContext.Set));
MethodInfo generic = dbSetMethod.MakeGenericMethod(property.DeclaringType);
var asQueryableMethod = generic.ReturnType.GetMethod("AsQueryable");
var result = asQueryableMethod.Invoke(this.DbContext, null);
But when I debug the code, I get a null in the line:
var asQueryableMethod = generic.ReturnType.GetMethod("AsQueryable");
Apparently, the dbContext.Set<TUnknownType>() does not have the AsQueryable method. That method is an extension method coming from Linq I guess.
What am I missing? Why is the method unavailable?
That's right, DbSet<T> implements IQueryable<T>, which exposes AsQueryable<T>() extension method.
C# offers two ways to invoke an extension method - as an instance method, i.e.
this.DBContext.Set<UnknownType>().AsQueryable();
or as a static method, i.e.
Queryable.AsQueryable(this.DBContext.Set<UnknownType>());
Reflection APIs, on the other hand, support only the second approach, i.e. the static method way of obtaining and invoking the method. You should get MethodInfo for generic Queryable.AsQueryable, and pass it an appropriate generic type parameter to make a MethodInfo object suitable for invocation.
My ultimate goal is to create a function that will dynamically pass method names to classes in the Hangfire library.
For example, here is the non-dynamic code which works:
RecurringJob.AddOrUpdate(() => myFunction(), Cron.Hourly)
The type of the first argument for AddOrUpdate is Expression<Action>. My first step was to use reflection to dynamically insert the function name:
Type thisControllerType = this.GetType();
MethodInfo method = thisControllerType.GetMethod(methodName); //methodName passed as string parameter
RecurringJob.AddOrUpdate(() => method.Invoke(this, null), Cron.Hourly);
When I check the Hangfire dashboard, it seems that this expression is being evaluated as MethodBase.Invoke. So I need help passing in the method name dynamically.
That may be enough info to answer my question, but another path I have taken is trying to generate the entire expression for the argument.
RecurringJob.AddOrUpdate(CreateCallExpression(method), Cron.Hourly);
public Expression<Action> CreateCallExpression(MethodInfo method)
{
//trying to pass in zero argument parameter, not sure if this syntax is correct
var parameter = System.Linq.Expressions.Expression.Parameter(typeof (Array));
return System.Linq.Expressions.Expression.Lambda<Action>(System.Linq.Expressions.Expression.Call(method, parameter));
}
In this case I am getting the exception {"Static method requires null instance, non-static method requires non-null instance.\r\nParameter name: method"}. I am working on that, but not sure if this is the road I should be going down. I have been working on this all day, so I was hoping someone might be able to help me speed up my learning.
Your second instance will work in creating a pointer to your specified method, but to solve your static issue you just need to modify the following line in one of 2 ways. First you can complete the static reference by declaring the method you seek to be static and modifying this line of code:
System.Linq.Expressions.Expression.Call(method, parameter);
You would have to provide a null parameter for the call method because if you are searching for a static method, then the compiler will know exactly what method signature you desire, because there will only exist 1. The line of code would be updated to:
System.Linq.Expressions.Expression.Call(null, method, parameter);
The second approach is to define the class or "instance" that correlates to the method so that the compiler knows what class to search against for the method signature. You would have to modify your code like this:
var myInstance = Expression.Parameter(typeof(MyClass), "inst");
System.Linq.Expressions.Expression.Call(myInstance, method, parameter)
I recommend looking at the documentation for Call so that you know exactly how the pointer is being created.
This may be a basic question, but I googled it and didn't find an answer. I hope you will help me. Consider I have an enum ContactNumberType:
string[] names = Enum.GetNames(typeof(ContactNumberType))
If I use the above, the compiler gives no error, but when I write:
string[] names = Enum.GetNames(ContactNumberType)
It says:
ContactNumberType is a type but used like a variable.
While the type of ContactNumberType is Enum, as far as I know, and the argument of method GetNames needs EnumType, so whats the issue with that?
You have to use typeof becuase the GetNames() method takes a parameter of type Type. Keep in mind that providing a type name is not the same as an instance of Type, which is an object that contains the details of that type.
To pass a type as a parameter, you have two basic choices:
Pass a Type instance
Use a generic
The first of these (which many older methods such as Enum.GetNames() does) requires you to get a Type instance from the type identifier, which we can do using the typeof() operator.
The second of these allows you to pass a type name as a parameter to a method or class to make that method or class generic and tends to be used on newer methods (generics were introduced in .NET 2.0):
var items = someList.OfType<SomeTypeName>();
Enum, however, doesn't have a generic form of GetNames() that allows this, though you could create something like one:
public static class EnumHelper
{
public static string[] GetNames<T>() where T : struct
{
return Enum.GetNames(typeof(T))
}
}
Which you could then call like:
string[] names = EnumHelper.GetNames<ContactNumberType>();
GetNames takes a parameter of type Type. The issue is that ContactNumberType is not a Type object. When you use the typeof operator, it returns the appropriate Type object.
Because typeof operator returns an object of Type
I'm fairly new to generics so I wonder if somebody can explain the following problem I'm having. In virtually all my controllers in an ASP.NET MVC application I need to return a filtered list (to populate a JqGrid as it happens where the user will have specified certain filtering criteria). Each controllers list method will return a different IQueryable list so I set about creating a generic method to handle this.
While I was creating my method I defined it in a specific controller. Everything compiled and I got the results I expected. Because I want to call this method from all my controllers I assumed I could simply create another static class, put the method in there and then call that method from all my controllers. But if I try to move the method to anywhere else other than the controller thats calling it, the compiler complains about the last line of the method with the following error:
The type arguments for method System.Linq.Queryable.Where<TSource>(System.Linq.IQueryable<TSource>,
System.Linq.Expressions.Expression<System.Func<TSource,bool>>)
cannot be inferred from the usage.
Try specifying the type arguments explicitly.
public static IQueryable<T> FilteredList<T>(IQueryable<T> list, string filters)
{
var qb = new QueryBuilder<T>();
var whereClause = qb.BuildWhereClause(filters);
return list.Where(whereClause);
}
I've tried list<T>.Where(whereClause) and list.Where<T>(whereClause) and just about every other combination, can anyone explain to me where I'm going wrong.
That would suggest that your BuildWhereClause method isn't returning the appropriate type.
The compiler is trying to infer the type of TSource from both list and whereClause. Now whereClause should be an Expression<Func<T, bool>> but I suspect it's not. Hover over the var in the declaration of whereClause to find out what it actually is. I wouldn't recommend using var when the return type isn't obvious.
Generic Methods in general are new to me. Need a method that returns a Collection of a generic type, but also takes a collection of the same generic type and takes
Expression<Func<GenericType, DateTime?>>[] Dates
parameter. T throughout the following function should be the same type, so right now I was using (simplified version):
private static Collection<T> SortCollection<T>(Collection<T> SortList, Expression<Func<T, DateTime>>[] OrderByDateTime)
{
return SortList.OrderBy(OrderByDateTime[0]);
}
but i'm receiving error:
Error: The type arguments for method
'System.Linq.Enumerable.OrderBy(System.Collections.Generic.IEnumberable,
System.Func)' cannot be
inferred from the usage. Try
specifying the type arguments
explicitly.
Is there anyway to do this?
Sorry for answering twice, but this is legitimately another solution.
You're passing in an Expression<Func<T, DateTime>> but Orderby wants a Func<T, DateTime>
You can either compile the expression:
return new Collection<T>(SortList.OrderBy(OrderByDateTime[0].Compile()).ToList());
or pass in straight out funcs as arguments:
private static Collection<T> SortCollection<T>(Collection<T> SortList, Func<T, DateTime>[] OrderByDateTime)
{
return new Collection<T>(SortList.OrderBy(OrderByDateTime[0]).ToList());
}
I'd recommend reading up on Expressions on msdn
In this situation, the compiler is failing to figure out what type arguments you intend to provide to the OrderBy method, so you'll have to supply them explicitly:
SortList.OrderBy<T, DateTime>(OrderByDateTime[0])
You'll probably want to call ToList() if you want a Collection to be returned