无法将“System.Object[]”类型的对象转换为“MyObject[]”,这是啥原因?
Posted
技术标签:
【中文标题】无法将“System.Object[]”类型的对象转换为“MyObject[]”,这是啥原因?【英文标题】:Unable to cast object of type 'System.Object[]' to 'MyObject[]', what gives?无法将“System.Object[]”类型的对象转换为“MyObject[]”,这是什么原因? 【发布时间】:2010-09-17 18:23:16 【问题描述】:场景:
我目前正在编写一个层来将 3 个类似的 Web 服务抽象为一个可用的类。每个 Web 服务都公开了一组具有共同性的对象。我创建了一组利用共性的中间对象。但是在我的层中,我需要在 Web 服务对象和我的对象之间进行转换。
在调用 Web 服务之前,我已使用反射在运行时创建适当的类型,如下所示:
public static object[] CreateProperties(Type type, IProperty[] properties)
//Empty so return null
if (properties==null || properties.Length == 0)
return null;
//Check the type is allowed
CheckPropertyTypes("CreateProperties(Type,IProperty[])",type);
//Convert the array of intermediary IProperty objects into
// the passed service type e.g. Service1.Property
object[] result = new object[properties.Length];
for (int i = 0; i < properties.Length; i++)
IProperty fromProp = properties[i];
object toProp = ReflectionUtility.CreateInstance(type, null);
ServiceUtils.CopyProperties(fromProp, toProp);
result[i] = toProp;
return result;
这是我的调用代码,来自我的一个服务实现:
Property[] props = (Property[])ObjectFactory.CreateProperties(typeof(Property), properties);
_service.SetProperties(folderItem.Path, props);
因此,每个服务都公开了一个不同的“Property”对象,我将其隐藏在我自己的 IProperty 接口实现之后。
反射代码在单元测试中工作,生成一个对象数组,其元素属于适当的类型。但是调用代码失败:
System.InvalidCastException:无法 'System.Object[]' 类型的强制转换对象 输入 'MyProject.Property[]
有什么想法吗?
我的印象是,只要包含的对象是可转换的,来自 Object 的任何转换都可以工作?
【问题讨论】:
【参考方案1】:替代答案:泛型。
public static T[] CreateProperties<T>(IProperty[] properties)
where T : class, new()
//Empty so return null
if (properties==null || properties.Length == 0)
return null;
//Check the type is allowed
CheckPropertyTypes("CreateProperties(Type,IProperty[])",typeof(T));
//Convert the array of intermediary IProperty objects into
// the passed service type e.g. Service1.Property
T[] result = new T[properties.Length];
for (int i = 0; i < properties.Length; i++)
T[i] = new T();
ServiceUtils.CopyProperties(properties[i], t[i]);
return result;
那么你的调用代码就变成了:
Property[] props = ObjectFactory.CreateProperties<Property>(properties);
_service.SetProperties(folderItem.Path, props);
更干净:)
【讨论】:
好吧,我确实说过“在 C# 2.0 及更高版本中,泛型通常是比数组协方差更好的选择。”。恐怕我不得不取消我对你上一个帖子的 +1 来 +1 这个...我今天全力以赴... 可以说,对于 Length==0 的情况,它会返回一些有点狡猾的东西——我自己会返回一个空数组... 已编辑以删除指控 :) 是的,返回 null 可能有点狡猾 - 但这是由 OP 决定的问题 :) 大声笑 - 没有采取任何指控;我有点同意原来的版本;-p 这是一个更好的解决方案,所以切换答案(对不起 Marc!)。【参考方案2】:基本上没有。数组协方差有一些有限的用途,但最好简单地知道您想要哪种类型的数组。有一个通用的 Array.ConvertAll 很简单(至少,使用 C# 3.0 更容易):
Property[] props = Array.ConvertAll(source, prop => (Property)prop);
C# 2.0 版本(含义相同)不太吸引眼球:
Property[] props = Array.ConvertAll<object,Property>(
source, delegate(object prop) return (Property)prop; );
或者只是创建一个合适大小的新属性[]并手动复制(或通过Array.Copy
)。
作为您可以使用数组协方差做的事情的一个例子:
Property[] props = new Property[2];
props[0] = new Property();
props[1] = new Property();
object[] asObj = (object[])props;
这里,“asObj”仍然是Property[]
- 它可以简单地以object[]
访问。在 C# 2.0 及更高版本中,泛型通常是比数组协方差更好的选择。
【讨论】:
谢谢,这行得通。 convertall 与 copy 对性能有何影响? ConvertAll 每次都会涉及一个委托调用,其中 Copy 应该只在箍下使用 Buffer.BlockCopy。所以复制应该更快。 ConvertAll 更容易输入(适合中小型字体),并且更灵活:您可以进行重要的投影。 另外 - ConvertAll 将处理转换而不是强制转换; Array.Copy 不能这样做,因为不能保证原始对象和目标对象的大小相同(这对于 Buffer.BlockCopy 是必需的)【参考方案3】:正如其他人所说,数组必须是正确的类型才能开始。其他答案已经展示了如何在事后转换真正的 object[],但是您可以创建正确类型的数组以使用 Array.CreateInstance 开始:
object[] result = (object[]) Array.CreateInstance(type, properties.Length);
假设 type
是一个引用类型,这应该可以工作 - 数组将是正确的类型,但您将它用作 object[]
只是为了填充它。
【讨论】:
很多时候我只是陷入了这个值类型的陷阱,然后我记得:) 好消息!谢谢,*** 需要辅助答案。知道类型会很好,但我正在尝试编写尽可能少的代码。这样我以后可以添加更多服务,而不必再次编写映射代码。我目前必须用 3 种方法编写 3 个循环。 Rob:您已经将类型作为参数传递给方法,不是吗?我是不是误会了什么? 是的……不知道我在说什么!【参考方案4】:您不能像这样转换数组 - 它返回一个对象数组,这与对象不同。试试Array.ConvertAll
【讨论】:
【参考方案5】:没错,但这并不意味着您可以将 Object 类型的容器转换为其他类型的容器。 Object[] 与 Object 不同(尽管奇怪的是,您可以将 Object[] 转换为 Object)。
【讨论】:
好吧,有点迂腐,而且 Object[] 是 一个对象......所以演员表并不那么奇怪。 .NET 中的一切都是对象【参考方案6】:在 C# 2.0 中,您可以使用反射来做到这一点,而无需使用泛型并且在编译时不知道所需的类型。
//get the data from the object factory
object[] newDataArray = AppObjectFactory.BuildInstances(Type.GetType("OutputData"));
if (newDataArray != null)
SomeComplexObject result = new SomeComplexObject();
//find the source
Type resultTypeRef = result.GetType();
//get a reference to the property
PropertyInfo pi = resultTypeRef.GetProperty("TargetPropertyName");
if (pi != null)
//create an array of the correct type with the correct number of items
pi.SetValue(result, Array.CreateInstance(Type.GetType("OutputData"), newDataArray.Length), null);
//copy the data and leverage Array.Copy's built in type casting
Array.Copy(newDataArray, pi.GetValue(result, null) as Array, newDataArray.Length);
您可能希望将所有 Type.GetType("OutputData") 调用和 GetProperty("PropertyName") 替换为从配置文件中读取的一些代码。
我还会使用泛型来指示 SomeComplexObject 的创建
T result = new T();
Type resultTypeRef = result.GetType();
但我说过你不需要使用泛型。
不保证性能/效率,但确实有效。
【讨论】:
以上是关于无法将“System.Object[]”类型的对象转换为“MyObject[]”,这是啥原因?的主要内容,如果未能解决你的问题,请参考以下文章
无法将对象类型“System.Web.Mvc.HtmlHelper` 1 [System.Object]”转换为“System.Web.Mvc.HtmlHelper”
无法将类型为“Newtonsoft.Json.Linq.JObject”的对象转换为类型“System.Collections.Generic.Dictionary`2[System.String,S
无法将System.Object []转换为类型{System.String,System.Management.Automation.ScriptBlock}
无法将类型“System.Nullable`1”强制转换为类型“System.Object”。LINQ to Entities 仅支持强制转换 EDM 基元或枚举类型。