此问题已完全修改。要查看原始版本,请参阅编辑记录
我想我应该解释一下我的情况和问题的背景。
我正在检查使用自定义属性注释的属性的类型。然后我获得该属性的值,但是作为object
:
IEnumerable<object> propertiesValues = myType.GetProperties().Where(p => p.GetCustomAttributes(typeof(MyCustomAttribute)) != null);
一旦我拥有了这些值,我想在它们上调用我的方法Map
,根据它们的类型将它们转换为不同的对象。这是因为我的数据库API需要这样。
foreach(object value in propertiesValues)
{
object mapped = Map(value);
// ...
}
我需要将所有IEnumerable<NumberType>
值转换为IEnumerable<string>
。所以我的第一个方法是:
public static object Map(object value)
{
if(value is IEnumerable<short> || value is IEnumerable<int> || ....)
return ((IEnumerable<object>) value).Cast<string>();
}
但是,这会引发运行时异常,因为我无法将IEnumerable<int>
强制转换为IEnumerable<object>
。
答案 0 :(得分:13)
您想要的功能称为协方差,只有当类型参数都是引用类型时,C#才支持IEnumerable<T>
。也就是说,IEnumerable<string>
可能会转换为IEnumerable<object>
,但IEnumerable<int>
可能不会如此转换。
原因是:当您获得一系列字符串时,这些字符串引用是已经合法对象引用。但是当一个int被装箱时,它只会成为一个合法的对象引用;编译器在哪里可以插入装箱操作?它没有,所以转换是非法的。
要将IEnumerable<int>
转换为IEnumerable<object>
,您必须通过投影明确地进行装箱:
from number in items select (object)item
或
items.Select(item => (object) item)
那将是IEnumerable<object>
,然后你就可以做你喜欢的事了。
或使用Cast序列运算符
items.Cast<object>()
做同样的事情。或使用其查询表单:
from object item in items select item
或者只是使用非泛型IEnumerable
,它会为您提供一系列盒装值,如果它实际上是一系列结构。
我注意到您通过IEnumerable<object>
扩展方法将IEnumerable<string>
投射到Cast
的计划注定要失败。这些物品将是盒装的。盒装的int不能拆箱到字符串。
看起来你在这里打击类型系统而不是使用它。也许你应该描述你真正的问题,而不是你试图围绕类型系统进行最终运行来解决它。
答案 1 :(得分:2)
你为什么不这样做
<a class="twitter-timeline"
data-widget-id="600720083413962752"
href="https://twitter.com/TwitterDev"
width="300"
height="300">
Tweets by @TwitterDev
</a>
您也可以更新var source = ... /// IEnumerable<???>
var destination = source.Select(item => item.ToString());
的签名:
Map
或
object Map<TItem, TSource>(TSource source)
: where TSource : IEnumerable<TItem>