我有BindingSource
DataSource
(定义为对象)在运行时可以是任何类型的IEnumerable
类(例如IList<Foo>
)。我需要将其转换为IQueryable<T>
,以便将其传递给通用扩展名:
IOrderedQueryable<TEntity> OrderUsingSortExpression<TEntity>(this IQueryable<TEntity> source, string sortExpression) where TEntity : class
到目前为止,我有这个:
string order = "Message ASC";
Type thetype = bsTotalBindingSource.DataSource.GetType().GetGenericArguments()[0];
IEnumerable<object> totalDataSource = ((IEnumerable<object>)(bsTotalBindingSource.DataSource));
//Blowing up on this next line with 'System.Linq.Queryable is not a GenericTypeDefinition. MakeGenericType may only be called on a type for which Type.IsGenericTypeDefinition is true.'
MethodInfo asQueryableMethod = typeof(Queryable).MakeGenericType(thetype).GetMethod("AsQueryable", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(IQueryable<>) }, null);
MethodInfo genericAsQueryableMethod = asQueryableMethod.MakeGenericMethod(thetype);
MethodInfo orderUsingSortExpressionMethod = GetType().GetMethod("OrderUsingSortExpression");
MethodInfo genericUsingSortExpressionMethod = orderUsingSortExpressionMethod.MakeGenericMethod(thetype);
bsTotalBindingSource.DataSource = genericUsingSortExpressionMethod.Invoke(this, new object[] { genericAsQueryableMethod.Invoke(totalDataSource, null), order });
正如您所看到的,此处的最终目标是能够从DataSource中获取某些内容,将IEnumerable<T>
的RuntimeType设置为T
可以为什么,然后调用AsQueryable<T>
它可以传递给接受IQueryable<T>
的函数。
EDIT 经过四处寻找具体找到我正在寻找的方法后,我对这个问题有了更深入的了解。它现在看起来像这样:
string order = "Message ASC";
Type thetype = bsTotalBindingSource.DataSource.GetType().GetGenericArguments()[0];
//Returns the AsQueryable<> method I am looking for
MethodInfo asQueryableMethod = typeof(Queryable).MakeGenericType(thetype).GetMethods()[1];
MethodInfo genericAsQueryableMethod = asQueryableMethod.MakeGenericMethod(thetype);
MethodInfo orderUsingSortExpressionMethod = typeof(SortExtension)GetType().GetMethods()[0];
MethodInfo genericUsingSortExpressionMethod = orderUsingSortExpressionMethod.MakeGenericMethod(thetype);
bsTotalBindingSource.DataSource = genericUsingSortExpressionMethod.Invoke(this, new object[] { genericAsQueryableMethod
//blows up here with 'Object of type 'System.RuntimeType' cannot be converted to type 'System.Collections.Generic.IEnumerable`1[LogRecordDTO]'.'
.Invoke(bsTotalBindingSource.DataSource, new object[] {thetype}), order });
答案 0 :(得分:3)
您说要将IEnumerable<T>
转换为IQueryable<T>
,其中T的类型未知。
private void Test<T>(IEnumerable<T> x)
{
var queryableX = x.AsQueryable();
}
注意:您需要using System.Linq
。
答案 1 :(得分:0)
我认为以下内容可能有效:
// Get generic type argument for everything
Type theType = bsTotalBindingSource.DataSource
.GetType().GetGenericArguments()[0];
// Convert your IEnumerable<?>-in-an-object to IQueryable<?>-in-an-object
var asQueryable =
// Get IEnumerable<?> type
typeof(IEnumerable<>)
.MakeGenericType(new[] { theType })
// Get IEnumerable<?>.AsQueryable<?> method
.GetMethod(
"AsQueryable",
new Type[] { theType },
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.Public)
// Call on the input object
.Invoke(bsTotalBindingSource.DataSource, new object[0]);
// Sort this queryable
var asSortedQueryable =
// Get the YourType<?> generic class your sorting generic method is in?
// If your class isn't generic I guess you can skip the MakeGenericType.
typeof(yourtype)
.MakeGenericType(new[] { theType })
// Get the OrderUsingSortExpression<?> method
.GetMethod(
"OrderUsingSortExpression",
new Type[] { theType },
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.Public)
// Call on the IQueryable<?> object
.Invoke(dataSource, new object[] { order });
// Set this object to the data source
bsTotalBindingSource.DataSource = asSortedQueryable;
作为免责声明,我对此并不是很清楚。例如从AsQueryable<T>
获取IEnumerable<T>
时,是否需要传递泛型参数?但我做相信你想要做的事情是可能的,并且 需要反思,我做认为这是大致正确的。
答案 2 :(得分:0)
我认为最简单的方法是重载(或添加扩展方法)到你想要调用的方法,将IEnumerable作为参数。然后只需从中调用另一个方法。这是我的意思的一个例子。
public class MyTestClass
{
public void Run()
{
List<string> myList = new List<string>() { "one", "two" };
object myListObject = (object)myList;
Test(myListObject);
}
private void Test(object myListObject)
{
Type myGenericType = myListObject.GetType().GetGenericArguments().First();
MethodInfo methodToCall = typeof(MyTestClass).GetMethods().Single(
method => method.Name.Equals("GenericMethod") && method.GetParameters().First().Name.Equals("myEnumerableArgument"));
MethodInfo genericMethod = methodToCall.MakeGenericMethod(myGenericType);
genericMethod.Invoke(this, new object[] { myListObject });
}
public void GenericMethod<T>(IQueryable<T> myQueryableArgument)
{
}
public void GenericMethod<T>(IEnumerable<T> myEnumerableArgument)
{
GenericMethod<T>(myEnumerableArgument.AsQueryable());
}
}