Pass Type to IQueryable at runtime - c#

Is it possible to pass type to IQueryable to realize at run time.
Like,
//Get type at runtime
Type type = Type.GetType("fully qualified class name");
IQueryable<type> test = // <-returned object of this type
Actual problem as below:
Below I am able to get right side object with specific type, but that is not casting to type of query variable. Also I will have known type for query.
Dictionary<string, Type> myDictionary = new Dictionary<string, Type>()
{
{ "tableName", typeof(tableName) }
};
//Below I am able to get right side object with specific type, but that is not casting to type of query variable. Also I will have known type for query.
IQueryable<Type> query= EFContext.Set(myDictionary[tableName]).AsQueryable();
Later using this query object to select data by passing select/where condition dynamically.
var data = query.Select(x=> new
{
id= x.id,
name= x.name .. etc
}).ToList();
Later I need to use this test variable to dynamically query data.
Also please suggest any alternative to resolve this scenario.

If you have an example of the IQueryable type you need, you can use an generic method to capture the type - this one returns a null of the proper type:
public static T NullByExample<T>(this T _) where T : class => (T)null;
If you have an example of the items returned, you can use an extension like:
public static IEnumerable<T> EmptyByExample<T>(this T _) => Enumerable.Empty<T>();
Either use AsQueryable on the result:
var test = EmptyByExample(classObject).AsQueryable();
or create an IQueryable variant - unfortunately, there isn't really an IQueryable equivalent to Enumerable.Empty:
public static IQueryable<T> EmptyQueryByExample<T>(this T _) => Enumerable.Empty<T>().AsQueryable();
var test = EmptyQueryByExample(queryObject);
Otherwise, as mentioned, you are in the world of reflection, which probably indicates you are doing something wrong. The problem is you will find you can only get test to be of type object in that case, because the compiler can't know what type represents and e.g. var is a compile time shorthand, unless you want to use dynamic (and you shouldn't do that either).

There are ways to do what you're asking via reflection, but maintainability will be limited. You're probably better off creating a shared interface to your types and writing a generic method, something like this:
interface IMyInterface
{
string SomeProperty {get;set;}
}
class MyClass : IMyInterface
{
public string SomeProperty {get;set;}
}
IQueryable<T> SomeMethod<T>() where T : IMyInterface, new()
{
var result = new List<T>() {
new T() { SomeProperty = "a"},
new T() { SomeProperty = "b"}
};
return result.AsQueryable();
}
So a call to the generic method might be:
var temp = SomeMethod<MyClass>();

Related

How do I get the type of a generic parameter on IEnumerable<object>?

I created a method to tell me what the Type of the object in an generic IEnumerable is.
It seemed like a straightforward affair but I got unexpected results when I tried passing the value collection from a Dictionary to my method.
I would like to know how to fix the method to return the right result and ideally I would also like an explanation of why I get the results that I get.
//sample class (target type to get)
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
//method that extracts the type
public Type GetItemType(IEnumerable<object> collection)
{
Type collectionType = collection.GetType();
Type[] genericArguments = collectionType.GetGenericArguments();
return genericArguments[0];
}
//sample data for test
var folk = new Dictionary<string, Person>();
folk.Add("Joe", new Person() { Name="Joseph Stalin", Age = 43 });
folk.Add("Tony", new Person() { Name="Winston Churchill", Age = 65 });
IEnumerable<Person> people = folk.Values;
Type itemType = GetItemType(people);
The itemType is "System.String" and not "Person".
It seems to take the type generic parameters from the actual Dictionary and not the values collection.
The problem here is actually a subtle one. What's going on is that the actual runtime type of folk.Values is a nested class of Dictionary. Specifically it's Dictionary<string, Person>.ValueCollection. Effectively the generic parameters get moved onto the ValueCollection type, and the first one ends up being string.
Ideally, all you should really have to do is change the method signature:
public Type GetItemType<T>( IEnumerable<T> collection )
{
return typeof( T );
}
To get around this without introducing an actual generic parameter you need to do something like this:
public Type GetItemType(IEnumerable<object> collection)
{
Type collectionType = collection.GetType();
collectionType.Dump();
return collectionType.GetInterfaces()
.Where( iface => iface.IsGenericType )
.Where( iface => iface.GetGenericTypeDefinition() == typeof( IEnumerable<> ) )
.Select( iface => iface.GetGenericArguments()[0] ).FirstOrDefault();
}
In this case we enumerate the interfaces the collection type implements looking for IEnumerable<> and then pull off its generic argument. Beware, this can run into problems if you find a type that implements IEnumerable<> multiple times with different generic argument types.
The problem you're facing is that there's an underlying type behind IEnumerable<object>, and that type in your case is Dictionary<string, Person>.ValueCollection.
You can see that if you use the debugger and inspect collectionType. To get around this, you could turn the collection into a list by adding .ToList() when initializing people:
IEnumerable<Person> people = folk.Values.ToList();
Now the type behind IEnumerable<object> is List<Person> and should give you the result you're looking for.
An alternative "fix" is to change your method signature to:
public Type GetItemType<T>(IEnumerable<T> collection)
That will return a Person type as well even without turning the Values collection into a list.
Your GetItemType method gets an IEnumerable<object>. Is it guaranteed that all the items in the IEnumerable will be of the same type?
If not, you need to return an IEnumerable of types.
If yes, you need only look at the very first one, and return collection.First().GetType()
Is this what you were looking for?
Oh, actually, check out #itsme86 comment, that's a cleaner way to do what you want to do

How to cast value returned by Invoke to IEnumerable<type> where type is some variable of type T?

I have the situation, where I want to call some generic method on another object and get IEnumerable result.
private void SomeFunction(Type type)
{
var method = context.GetType()
.GetMethods()
.FirstOrDefault(_ => _.Name == "GetStorage" && _.IsGenericMethod);
var storage = getStorage.MakeGenericMethod(type)
.Invoke(context, new object[] {})
.AsEnumerable();
//Some magic needed here. Something like Cast<type>,
//but type - variable
//More code ...
}
Could anyone suggest me how to figure out this situation. Thank you.
I have already seen this and similar questions:
Casting Results from Generic Method Invocation?
But they doesn't answer on my question, how to do same, when I don't know type, to which I want to cast, and type is stored as variable.
I can't makeSomeFunction a generic method, because the real situation is that I am iterating some list with System.Type and calling lambda (i. e. SomeFunction) on each element
There are some things you need to do to get what you want. You say you want to have a lambda, but that means that you need to define that lambda, which is on a type you do not know yet. You can redesign your lambda into an interface.
Also, I find it much easier to define a generic class that does exactly what I want. By creating an instance of this class through reflection, and only there, I can implement the rest of the class in a strong typed way. This takes away the 'not knowing what type I have' in most places.
Like this. First, the executor interface:
public interface ISomeFunctionExecutor
{
void Execute(SomeContext context);
}
Then the interface that I need to implement on the entities, which is the lambda so to speak.
public interface IEntityWithSomeFunction
{
void SomeFunction();
}
Now the implementation of the executor.
public class SomeFunctionExecutor<TType> : ISomeFunctionExecutor
{
public void Execute(SomeContext context)
{
var data = context.GetStorage<TType>().Cast<IEntityWithSomeFunction>();
foreach (var item in data)
{
item.SomeFunction();
}
}
}
And finally, the usage of it all:
// Usage:
SomeContext context = new SomeContext();
Type type = typeof(SomeEntity);
var executorType = typeof(SomeFunctionExecutor<>).MakeGenericType(type);
var executor = Activator.CreateInstance(executorType) as ISomeFunctionExecutor;
if (executor != null)
{
executor.Execute(context);
}
Basically the point is: define a generic class to do what you need to do where you do know the type, and create an instance of this class using reflection. It makes it much easier than having a whole method where you do not know the type.

How to filter a collection of delegates based on their parameter's generic type in C#?

I have a collection of delegates:
IList<Action<ISomeInterface>> _delegates = new List<Action<ISomeInterface>>();
And a method* to add delegates to it**:
public void AddDelegate<T>(Action<T> del) where T : ISomeInterface
{
_delegates.Add(si => del((T)si));
}
Now I want to filter the delegates collection based on the concrete type the delegate is constructed with:
var aDelegates = _delegates.Where(d => d is Action<SomeInterfaceImplA>);
foreach(var del in aDelegates)
{
....
}
Which will return all delegates, not only Action<SomeInterfaceImplA> delegates. So my question is, what predicate should be used in the Where clause to get the correct subset from the filtering? Full code example is available here.
* A fluent API (generic) method is using it hence the use of a generic type here
** Based on the answer here
This not be the prettiest thing ever, but it works
var aDelegates = someClass.Delegates.Where(d =>
d.Method.DeclaringType.GenericTypeArguments.FirstOrDefault().IsAssignableFrom(typeof(SomeInterfaceImplA)));
I am not sure that the construction you have currently makes any sense. You may want to change what you are doing if you want to filter your delegates by concrete expected implementation argument type, by changing this:
IList<Action<ISomeInterface>> _delegates = new List<Action<ISomeInterface>>();
to this:
IDictionary<Type, List<Action<ISomeInterface>>> _delegates =
new Dictionary<Type, List<Action<ISomeInterface>>>();
And the AddDelegate method to
public void AddDelegate<T>(Action<T> del) where T : ISomeInterface
{
var list = default(List<Action<ISomeInterface>>);
if (!_delegates.TryGetValue(typeof(T), out list))
_delegates[typeof(T)] = list = new List<Action<ISomeInterface>>();
list.Add(si => del((T)si));
}
And use the dictionary to filter by argument type.
The reason why your current code will not work, is that all of the registered actions are actually of type Action<ISomeInterface>, that their method body (si => del((T)si) performs a dangerous cast of its argument to a type T does not change that.

Can I check a property on a generic object by passing in a lambda expression to get the parameter?

Simple example, I have a Cat object with a Name property.
I have a class with a method called PrintName<T>(T objectToPrint)
I can't do Console.WriteLine(objectToPrint.Name) because it's type T.
So can I pass in the parameter as a linq expression that gets the name? Something like;
Cat c = new Cat("Bernard the Cat");
PrintName(cat, parameter: c => c.Name);
Then PrintName can just do
Console.WriteLine(cat.RunLinq(parameter));
Well, you could use an Interface, but if the property can change, you could do.
First solution : if you need the property's name
PrintName<T>(T objectToPrint, Expression<Func<T, object>> property)
usage
PrintName(cat, c=> c.Name)
Then to get the "name" of the property, something like that.
var name = (property.Body as MemberExpression).Member.Name
Second solution : if you need the property's value
if you want the value of the property, use a Func<T, object> func parameter
// object if you don't know the type of the property,
// you can limit it to string if needed, of course
PrintName<T>(T objectToPrint, Func<T, object> func)
usage
PrintName(cat, c => c.Name)
then
var value = func(cat)
The way this is usually done is to pass the type of cat through using generics:
void PrintName<T>(T cat, Func<T, string> parameter) {
Console.WriteLine(parameter(cat));
}
The delegate can use the exact type of T and therefore access Name. LINQ works that way a lot (OrderBy, ...). If we replaced T by object this pattern would not work because the type would not be passed through.
You can define an interface and implement it at the each object that should support printing
interface IPrintable
{
string Name{get;}
}
class Cat : IPrintable
{
string Name{get{retrun "Dog";}}
}
void PrintName(IPrintable objectToPrint)
{
Console.WriteLine(objectToPrint.Name);
}
var cat = new Cat();
PrintName(cat);
You can use reflection or dynamic to implement it without interface implementation
void PrintName<T>(T objectToPrint)
{
dynamic o = (dynamic)objectToPrint;
Console.Writeline(o.Name);
}

Typecast to a type from just the string representation of the type name

sTypeName = ... //do some string stuff here to get the name of the type
/*
The Assembly.CreateInstance function returns a type
of System.object. I want to type cast it to
the type whose name is sTypeName.
assembly.CreateInstance(sTypeName)
So, in effect I want to do something like:
*/
assembly.CreateInstance(sTypeName) as Type.GetType(sTypeName);
How do I do that? And, what do I take on the left side of the assignment expression, assuming this is C# 2.0. I don't have the var keyword.
Usually you let all classes, you want to instantiate this dynamically, implement a common interface, lets say IMyInterface. You can create an instance from the classname string like this:
Assembly asm = Assembly.GetExecutingAssembly();
string classname = "MyNamespace.MyClass";
Type classtype = asm.GetType(classname);
// Constructor without parameters
IMyInterface instance = (IMyInterface)Activator.CreateInstance(classtype);
// With parameters (eg. first: string, second: int):
IMyInterface instance = (IMyInterface)Activator.CreateInstance(classtype,
new object[]{
(object)"param1",
(object)5
});
Even if you dont have a common interface, but know the name of the method (as string) you can invoke your methods like this (very similar for properties, event and so on):
object instance = Activator.CreateInstance(classtype);
int result = (int)classtype.GetMethod("TwoTimes").Invoke(instance,
new object[] { 15 });
// result = 30
The example class:
namespace MyNamespace
{
public class MyClass
{
public MyClass(string s, int i) { }
public int TwoTimes(int i)
{
return i * 2;
}
}
}
Unfortunately there's no way in .NET to do what you want.
Possible partial solutions are:
If you know the type at compile-time (unlikely, since you're creating it at run-time from a string) then simply cast to that type:
YourType t = (YourType)Activator.CreateInstance(sTypeName);
If you know that all the possible types will implement a specific, common interface then you can cast to that interface instead:
IYourInterface i = (IYourInterface)Activator.CreateInstance(sTypeName);
If you can't do either of the above then, unfortunately, you're stuck with object and reflection.
.
Define a generic method in your class, and then you can cast like this:
public T Cast<T>(object obj)
{
return (T) obj;
}
string sTypename = "SomeClassName";
MethodInfo cast = this.GetType().GetMethod("Cast");
MethodInfo genericCast = cast.MakeGenericMethod(new Type[] { Type.GetType(sTypename) });
Object castedValue = genericCast.Invoke(this, new object[] { instanceToBeCasted });
But then I think, what is the point of such casting if you cannot store the casted value in a variable of the actual type, precisely because you don't know the actual type at the time of writing the code?

Categories

Resources