[英]How can I cast IEnumerable<?> to IEnumerable<string>?
This question was completely edited. 这个问题已完全编辑。 To see the original one, see the edit history
要查看原始版本,请参阅编辑历史记录
I think I should explain a little bit of my situation and context of the problem. 我想我应该解释一下我的情况和问题的背景。
I'm inspecting a type for a property annotated with a custom attribute. 我正在检查使用自定义属性注释的属性的类型。 I then get the value of that property, but as an
object
: 然后我获取该属性的值,但作为一个
object
:
IEnumerable<object> propertiesValues = myType.GetProperties().Where(p => p.GetCustomAttributes(typeof(MyCustomAttribute)) != null);
Once I have these values I want to call my method Map
on them, which converts them to a different object depending on their type. 一旦我有这些值,我想在它们上面调用我的方法
Map
,它根据它们的类型将它们转换为不同的对象。 This is because my database API requires so. 这是因为我的数据库API需要这样做。
foreach(object value in propertiesValues)
{
object mapped = Map(value);
// ...
}
I need all IEnumerable<NumberType>
values, to be converted to IEnumerable<string>
. 我需要所有
IEnumerable<NumberType>
值,才能转换为IEnumerable<string>
。 So my first approach was: 所以我的第一个方法是:
public static object Map(object value)
{
if(value is IEnumerable<short> || value is IEnumerable<int> || ....)
return ((IEnumerable<object>) value).Cast<string>();
}
However, this is throwing a runtime exception, as I cannot cast IEnumerable<int>
to IEnumerable<object>
for example. 但是,这会引发运行时异常,因为我无法将
IEnumerable<int>
IEnumerable<object>
为IEnumerable<object>
。
The feature you want is called covariance , and C# supports it on IEnumerable<T>
only when the type arguments are both reference types. 您想要的功能称为协方差 ,只有当类型参数都是引用类型时,C#才会在
IEnumerable<T>
上支持它。 That is, IEnumerable<string>
may be converted to IEnumerable<object>
, but IEnumerable<int>
may not be so converted. 也就是说,
IEnumerable<string>
可以转换为IEnumerable<object>
,但IEnumerable<int>
可能不会被转换。
The reason is: when you get a sequence of strings, those string references are already legal object references. 原因是:当您获得一系列字符串时,这些字符串引用已经是合法的对象引用。 But an int only becomes a legal object reference when it is boxed;
但是当一个int被装箱时,它只会成为一个合法的对象引用; where does the compiler know to insert the boxing operation?
编译器在哪里可以插入装箱操作? It doesn't, so the conversion is illegal.
它没有,所以转换是非法的。
To convert an IEnumerable<int>
to IEnumerable<object>
you have to do the boxing explicitly via a projection: 要将
IEnumerable<int>
转换为IEnumerable<object>
您必须通过投影明确地进行装箱:
from number in items select (object)item
or 要么
items.Select(item => (object) item)
That will be IEnumerable<object>
, and you can then do what you like to that. 那将是
IEnumerable<object>
,然后你就可以做你喜欢的了。
Or use the Cast sequence operator 或者使用Cast序列运算符
items.Cast<object>()
which does the same thing. 它做同样的事情。 Or use its query form:
或使用其查询表单:
from object item in items select item
Or simply use the non-generic IEnumerable
, which gives you a sequence of boxed values if in fact it is a sequence of structs. 或者简单地使用非泛型
IEnumerable
,它为您提供一系列盒装值,如果它实际上是一系列结构。
I note though that your plan of then casting IEnumerable<object>
to IEnumerable<string>
via the Cast
extension method is doomed to failure. 我注意到你通过
Cast
扩展方法将IEnumerable<object>
为IEnumerable<string>
的计划注定要失败。 Those items will be boxed ints. 这些物品将是盒装的。 Boxed ints cannot be unboxed to string.
盒装的int不能拆箱到字符串。
It seems like you are fighting the type system here instead of working with it. 看起来你在这里打击类型系统而不是使用它。 Perhaps you should describe your real problem, rather than your attempts to do an end-run around the type system to solve it.
也许您应该描述您的真实问题,而不是您尝试围绕类型系统进行最终运行来解决它。
Why don't you do this 你为什么不这样做?
var source = ... /// IEnumerable<???>
var destination = source.Select(item => item.ToString());
You could update Map
's signature as well: 你也可以更新
Map
的签名:
object Map<TItem, TSource>(TSource source)
: where TSource : IEnumerable<TItem>
or 要么
object Map<TItem>(IEnumerable<TItem> source)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.