在linq查询中转换泛型类型
本文关键字:转换 泛型类型 查询 linq | 更新日期: 2023-09-27 18:03:19
所以我有一个接受泛型类型参数的类,如果类型参数是给定类型的子类,则做一些特殊处理。
IEnumerable<T> models = ...
// Special handling of MySpecialModel
if (filterString != null && typeof(MySpecialModel).IsAssignableFrom(typeof(T)))
{
var filters = filterString.Split(...);
models =
from m in models.Cast<MySpecialModel>()
where (from t in m.Tags
from f in filters
where t.IndexOf(f, StringComparison.CurrentCultureIgnoreCase) >= 0
select t)
.Any()
select (T)m;
}
但是在最后一行
出现了异常Cannot convert type 'MySpecialModel' to 'T'
如果我改变代码使用as
而不是强制转换,我得到这个错误。
The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint.
我在这里错过了什么?
这个类需要可以接受任何类型参数,包括struct
和内置类型,所以在我的情况下,泛型约束不是一个合适的解决方案。
Do
Select(x => (MySpecialModel)x)
LINQ Cast<T>
方法只适用于将元素转换为元素已经存在的类型(例如基类型、派生类型或接口)。它不打算将能够被强制转换为目标类型的对象强制转换。(例如:new List<int>{1,2,3}.Cast<long>()
也会抛出异常
上面的答案没有错,但它没有解决问题。
仅仅因为你用反射证明了泛型参数绑定到给定类型,并不意味着编译器知道它是。为了做到这一点,你需要将T
实例转换为一个通用类型(例如object
),然后将其转换为特定类型。例:(将查询的最后一行改为select (T)(object)m
应该可以达到目的。
试试下面的
select (T)(object)m;
在运行时,您已经验证了T
是MySpecialModel
的子类型,但编译器在编译时无法访问此信息。它只看到两个不相关的类型:T
和MySpecialModel
之间的尝试转换。
要解决这个问题,你需要使用object
作为中间人。编译器理解如何将MySpecialModel
转换为object
,以及如何从object
转换为T
。
最直接的修复方法是先强制转换为object
,然后再强制转换为T
:
select (T)(object)m;
问题是您的检查发生在运行时,但编译器不知道T
必须是if
语句中MySpecialModel
的实例。因此,它只是看到您试图从MySpecialModel
转换为任意类型T
,这是不安全的,因此出现错误。
如果您知道泛型类型将始终是一个类,则可以在类中添加类型约束:
public class Test<T> where T : class {}
否则,按照smartcaveman的建议,通过对象执行双强制转换:
.Select(x => (T)(object)x);
要使用as
关键字,请将class
约束放在泛型参数上:
void MyMethod<T>(T item) where T : class
{
//...
}
您可以应用Nullable<T>
约束-它应该启用强制转换的可能性(至少使用"as")