C# 无法将“System.Object[]”类型的对象强制转换为“MyObject[]”,这是怎么回事?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/212429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unable to cast object of type 'System.Object[]' to 'MyObject[]', what gives?
提问by Rob Stevenson-Leggett
Scenario:
设想:
I'm currently writing a layer to abstract 3 similar webservices into one useable class. Each webservice exposes a set of objects that share commonality. I have created a set of intermediary objects which exploit the commonality. However in my layer I need to convert between the web service objects and my objects.
我目前正在编写一个层,将 3 个类似的 Web 服务抽象为一个可用的类。每个 Web 服务都公开一组共享共性的对象。我创建了一组利用共性的中间对象。但是,在我的图层中,我需要在 Web 服务对象和我的对象之间进行转换。
I've used reflection to create the appropriate type at run time before I make the call to the web service like so:
在像这样调用 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;
}
Here's my calling code, from one of my service implementations:
这是我的调用代码,来自我的服务实现之一:
Property[] props = (Property[])ObjectFactory.CreateProperties(typeof(Property), properties);
_service.SetProperties(folderItem.Path, props);
So each service exposes a different "Property" object which I hide behind my own implementation of my IProperty interface.
因此,每个服务都公开了一个不同的“属性”对象,我将其隐藏在我自己的 IProperty 接口实现后面。
The reflection code works in unit tests producing an array of objects whose elements are of the appropriate type. But the calling code fails:
反射代码在单元测试中工作,生成元素为适当类型的对象数组。但调用代码失败:
System.InvalidCastException: Unable to cast object of type 'System.Object[]' to type 'MyProject.Property[]
System.InvalidCastException:无法将“System.Object[]”类型的对象转换为“MyProject.Property[]”
Any ideas?
有任何想法吗?
I was under the impression that any cast from Object will work as long as the contained object is convertable?
我的印象是,只要包含的对象是可转换的,来自 Object 的任何强制转换都可以工作?
采纳答案by Jon Skeet
Alternative answer: generics.
替代答案:泛型。
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;
}
Then your calling code becomes:
然后您的调用代码变为:
Property[] props = ObjectFactory.CreateProperties<Property>(properties);
_service.SetProperties(folderItem.Path, props);
Much cleaner :)
干净多了:)
回答by Tom Ritter
You can't convert an array like that - it's returning an array of objects, which is different from an object. Try Array.ConvertAll
您不能像这样转换数组 - 它返回一个对象数组,这与对象不同。尝试Array.ConvertAll
回答by TheSmurf
That's correct, but that doesn't mean that you can cast containers of type Object to containers of other types. An Object[] is not the same thing as an Object (though you, strangely, could cast Object[] to Object).
这是正确的,但这并不意味着您可以将 Object 类型的容器转换为其他类型的容器。Object[] 与 Object 不同(尽管您很奇怪,可以将 Object[] 转换为 Object)。
回答by Marc Gravell
Basically, no. There are a few, limited, uses of array covariance, but it is better to simply know which type of array you want. There is a generic Array.ConvertAll that is easy enough (at least, it is easier with C# 3.0):
基本上,没有。数组协方差有一些有限的用途,但最好简单地知道您想要哪种类型的数组。有一个通用的 Array.ConvertAll 很容易(至少,使用 C# 3.0 更容易):
Property[] props = Array.ConvertAll(source, prop => (Property)prop);
The C# 2.0 version (identical in meaning) is much less eyeball-friendly:
C# 2.0 版本(含义相同)不太吸引眼球:
Property[] props = Array.ConvertAll<object,Property>(
source, delegate(object prop) { return (Property)prop; });
Or just create a new Property[] of the right size and copy manually (or via Array.Copy
).
或者只是创建一个合适大小的新 Property[] 并手动复制(或通过Array.Copy
)。
As an example of the things you cando with array covariance:
作为您可以使用数组协方差执行的操作的示例:
Property[] props = new Property[2];
props[0] = new Property();
props[1] = new Property();
object[] asObj = (object[])props;
Here, "asObj" is stilla Property[]
- it it simply accessible as object[]
. In C# 2.0 and above, generics usually make a better option than array covariance.
在这里,“asObj”仍然是一个Property[]
- 它可以简单地作为object[]
. 在 C# 2.0 及更高版本中,泛型通常是比数组协方差更好的选择。
回答by Jon Skeet
As others have said, the array has to be of the right type to start with. The other answers have shown how to convert a genuine object[] after the fact, but you can create the right kind of array to start with using Array.CreateInstance:
正如其他人所说,数组必须是正确的类型才能开始。其他答案已经展示了如何在事后转换真正的 object[],但您可以创建正确类型的数组,以使用Array.CreateInstance开始:
object[] result = (object[]) Array.CreateInstance(type, properties.Length);
Assuming type
is a reference type, this should work - the array will be of the correct type, but you'll use it as an object[]
just to populate it.
假设type
是引用类型,这应该可以工作 - 数组将是正确的类型,但您将使用它作为object[]
填充它。
回答by Mr. Graves
in C# 2.0 you cando this using reflection, without using generics and without knowing the desired type at compile time.
在 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);
}
}
You would want to replace all the Type.GetType("OutputData") calls and the GetProperty("PropertyName") with some code that reads from a config file.
您可能希望用一些从配置文件中读取的代码替换所有 Type.GetType("OutputData") 调用和 GetProperty("PropertyName")。
I would also use a generic to dictate the creation of SomeComplexObject
我还将使用泛型来指示 SomeComplexObject 的创建
T result = new T();
Type resultTypeRef = result.GetType();
But I said you didn't need to use generics.
但我说你不需要使用泛型。
No guarantees on performance/efficiency, but it does work.
不保证性能/效率,但它确实有效。