C# 将IEnumerable转换为IEnumerable<;T>;当T在编译时未知时
我有一个具有以下签名的排序扩展方法:C# 将IEnumerable转换为IEnumerable<;T>;当T在编译时未知时,c#,generics,C#,Generics,我有一个具有以下签名的排序扩展方法: public static IEnumerable<T> CustomSort<T>(this IEnumerable<T> source, string sortProperties) 公共静态IEnumerable CustomSort(此IEnumerable源,字符串sortProperties) 我们不久前写的,它一直在做它的事情。现在我正在创建一个自定义控件,DataSource属性是IEnumerable
public static IEnumerable<T> CustomSort<T>(this IEnumerable<T> source, string sortProperties)
公共静态IEnumerable CustomSort(此IEnumerable源,字符串sortProperties)
我们不久前写的,它一直在做它的事情。现在我正在创建一个自定义控件,DataSource属性是IEnumerable(非泛型)。
有没有办法获取非泛型IEnumerable中对象的类型
我确信“对自定义控件数据源进行排序”的问题已经解决了一百万次,但我似乎找不到解决方案。就我个人而言,我只想使用
DataSource.Cast()
然后就有了一个IEnumerable
,可以在CustomSort
函数中使用。我在这里假设这个函数已经可以处理任意对象了;根据第二个参数名判断,我猜您在其中使用了反射,所以应该没问题。只要确保它在思考时使用每个对象的GetType()
,而不是typeof(T)
,因为typeof(T)
显然是object
,它不会得到实际对象的字段列表
当然,如果您在编译时确实知道数据源中所有对象的类型,您可能希望改用该类型,例如:
DataSource.Cast<Customer>()
DataSource.Cast()
这里有一个基本问题,即一个类型可以同时为多个T实现IEnumerable-of-T。但如果我们排除这一情况,一种厚颜无耻的做法是:
void Evil<T>(IEnumerable<T> data) {...}
IEnumerable source = ...
dynamic cheeky = source;
Evil(cheeky);
void Evil(IEnumerable数据){…}
IEnumerable源=。。。
动态厚颜无耻=来源;
邪恶(厚颜无耻);
这基本上将这个问题转移到DLR上,让您的邪恶的T方法轻松解决。您可以创建一个扩展方法,在运行时返回正确的类型:
public static class LinqExtensions
{
public static Type GetElementType(this IEnumerable source)
{
var enumerableType = source.GetType();
if (enumerableType.IsArray)
{
return enumerableType.GetElementType();
}
if (enumerableType.IsGenericType)
{
return enumerableType.GetGenericArguments().First();
}
return null;
}
}
更新:我添加了一种机制,用于对非泛型IEnumerable
进行泛型特定的IEnumerable
排序
public static class SortingExtensions
{
public static IEnumerable<T> CustomSort<T>(this IEnumerable<T> source, string sortProperties)
{
// sort here
}
public static IEnumerable CustomSort(this IEnumerable source, string sortProperties)
{
var elementType = source.GetElementType();
var genericElementType = typeof (IEnumerable<>).MakeGenericType(elementType);
var sortMethod = typeof (SortingExtensions).GetMethod(
"CustomSort",
BindingFlags.Public | BindingFlags.Static,
null,
new [] {genericElementType, typeof (string)},
null);
return (IEnumerable) sortMethod.Invoke(null, new object[] {source, sortProperties});
}
}
公共静态类排序扩展
{
公共静态IEnumerable CustomSort(此IEnumerable源,字符串sortProperties)
{
//在这里分类
}
公共静态IEnumerable CustomSort(此IEnumerable源,字符串sortProperties)
{
var elementType=source.GetElementType();
var genericElementType=typeof(IEnumerable);
var sortMethod=typeof(SortingExtensions).GetMethod(
“自定义排序”,
BindingFlags.Public | BindingFlags.Static,
无效的
新[]{genericElementType,typeof(string)},
无效);
return(IEnumerable)sortMethod.Invoke(null,新对象[]{source,sortProperties});
}
}
关于MoveNext()你说得对。在我写这篇文章的时候,我已经删除了那一行,所以我是凭记忆写的。关于演员阵容,我试试看。谢谢大家!@EladLachmi:好的,那么我将冒昧地从您的问题中删除这一部分。CustomSort函数在反射中使用typeof(T)将排序构造为lambda表达式。我宁愿利用我们所拥有的,而不是创造一些新的东西(这需要经过QA等,等等…你知道它是怎样的:)。这假设源代码实际实现了IEnumerable
对于一些T
;NET中的许多数据源都源于泛型之前,因此实际上只实现了IEnumerable
,在这种情况下,您的代码会因RuntimeBinderException
@Timwi而崩溃。问题是如何“转换”它。只有当它确实为某些T实现了泛型版本时,才有可能强制转换它。我并不反对你的观点-我只是说这个依赖性在问题中是隐含的。@Timwi-Marc的假设是正确的,即非泛型IEnumerable(数据源)的起源是一些T的列表,这在编译时对我来说是未知的。因此它应该实现IEnumerable。在我的情况下,我将如何实现它?该方法是IEnumerable上的一种推广方法。。。我需要传递什么作为泛型参数?我理解您的解决方案的概念,但我缺乏实现它的机制:)@elad您不能将扩展语法用于动态-只需让您的扩展方法通过显式SomeType.邪恶(厚颜无耻)语法有趣的方法调用第二个方法。我也要试一试。关于排序方法,这或多或少是我们正在做的事情,但我们也考虑了多个属性的排序,每个属性都有自己的方向。我尝试了您的解决方案,但enumerableType.GetGenericArguments().First()会导致StackOverflowException。(很久没有了!:)我发现了问题。一旦该方法通过公共静态IEnumerable CustomSort(此IEnumerable源,字符串sortProperties),它将再次被调用,这将创建一个内循环,或者看起来是这样。在Invoke
中,您将source
作为第一个参数传递,它将再次调用非泛型方法。这会导致内循环。我将您的CustomSort
重命名为CustomSort2
,然后sortMethod
为空。